Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document some check_expr methods, and other misc hir_typeck tweaks #132297

Merged
merged 3 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{Diverges, Expectation, FnCtxt, Needs};

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[instrument(skip(self), level = "debug", ret)]
pub(crate) fn check_match(
pub(crate) fn check_expr_match(
&self,
expr: &'tcx hir::Expr<'tcx>,
scrut: &'tcx hir::Expr<'tcx>,
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ enum CallStep<'tcx> {
}

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(crate) fn check_call(
pub(crate) fn check_expr_call(
&self,
call_expr: &'tcx hir::Expr<'tcx>,
callee_expr: &'tcx hir::Expr<'tcx>,
Expand All @@ -75,8 +75,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.check_expr_with_expectation_and_args(
callee_expr,
Expectation::NoExpectation,
arg_exprs,
Some(call_expr),
Some((call_expr, arg_exprs)),
),
_ => self.check_expr(callee_expr),
};
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ pub(super) fn check_fn<'a, 'tcx>(
}

fcx.is_whole_body.set(true);
fcx.check_return_expr(body.value, false);
fcx.check_return_or_body_tail(body.value, false);

// Finalize the return check by taking the LUB of the return types
// we saw and assigning it to the expected return type. This isn't
Expand Down
95 changes: 53 additions & 42 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ use crate::{
};

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Check an expr with an expectation type, and also demand that the expr's
/// evaluated type is a subtype of the expectation at the end. This is a
/// *hard* requirement.
pub(crate) fn check_expr_has_type_or_error(
&self,
expr: &'tcx hir::Expr<'tcx>,
Expand Down Expand Up @@ -97,6 +100,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty
}

/// Check an expr with an expectation type, and also demand that the expr's
/// evaluated type is a coercible to the expectation at the end. This is a
/// *hard* requirement.
pub(super) fn check_expr_coercible_to_type(
&self,
expr: &'tcx hir::Expr<'tcx>,
Expand All @@ -108,6 +114,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.demand_coerce(expr, ty, expected, expected_ty_expr, AllowTwoPhase::No)
}

/// Check an expr with an expectation type. Don't actually enforce that expectation
/// is related to the expr's evaluated type via subtyping or coercion. This is
/// usually called because we want to do that subtype/coerce call manually for better
/// diagnostics.
pub(super) fn check_expr_with_hint(
&self,
expr: &'tcx hir::Expr<'tcx>,
Expand All @@ -116,6 +126,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_expr_with_expectation(expr, ExpectHasType(expected))
}

/// Check an expr with an expectation type, and also [`Needs`] which will
/// prompt typeck to convert any implicit immutable derefs to mutable derefs.
fn check_expr_with_expectation_and_needs(
&self,
expr: &'tcx hir::Expr<'tcx>,
Expand All @@ -133,10 +145,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty
}

/// Check an expr with no expectations.
pub(super) fn check_expr(&self, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> {
self.check_expr_with_expectation(expr, NoExpectation)
}

/// Check an expr with no expectations, but with [`Needs`] which will
/// prompt typeck to convert any implicit immutable derefs to mutable derefs.
pub(super) fn check_expr_with_needs(
&self,
expr: &'tcx hir::Expr<'tcx>,
Expand All @@ -145,33 +160,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_expr_with_expectation_and_needs(expr, NoExpectation, needs)
}

/// Invariant:
/// If an expression has any sub-expressions that result in a type error,
/// inspecting that expression's type with `ty.references_error()` will return
/// true. Likewise, if an expression is known to diverge, inspecting its
/// type with `ty::type_is_bot` will return true (n.b.: since Rust is
/// strict, _|_ can appear in the type of an expression that does not,
/// itself, diverge: for example, fn() -> _|_.)
/// Note that inspecting a type's structure *directly* may expose the fact
/// that there are actually multiple representations for `Error`, so avoid
/// that when err needs to be handled differently.
/// Check an expr with an expectation type which may be used to eagerly
/// guide inference when evaluating that expr.
#[instrument(skip(self, expr), level = "debug")]
pub(super) fn check_expr_with_expectation(
&self,
expr: &'tcx hir::Expr<'tcx>,
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
self.check_expr_with_expectation_and_args(expr, expected, &[], None)
self.check_expr_with_expectation_and_args(expr, expected, None)
}

/// Same as `check_expr_with_expectation`, but allows us to pass in the arguments of a
/// `ExprKind::Call` when evaluating its callee when it is an `ExprKind::Path`.
/// Same as [`Self::check_expr_with_expectation`], but allows us to pass in
/// the arguments of a [`ExprKind::Call`] when evaluating its callee that
/// is an [`ExprKind::Path`]. We use this to refine the spans for certain
/// well-formedness guarantees for the path expr.
pub(super) fn check_expr_with_expectation_and_args(
&self,
expr: &'tcx hir::Expr<'tcx>,
expected: Expectation<'tcx>,
args: &'tcx [hir::Expr<'tcx>],
call: Option<&'tcx hir::Expr<'tcx>>,
call_expr_and_args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
) -> Ty<'tcx> {
if self.tcx().sess.verbose_internals() {
// make this code only run with -Zverbose-internals because it is probably slow
Expand Down Expand Up @@ -216,9 +224,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};

let ty = ensure_sufficient_stack(|| match &expr.kind {
// Intercept the callee path expr and give it better spans.
hir::ExprKind::Path(
qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)),
) => self.check_expr_path(qpath, expr, Some(args), call),
) => self.check_expr_path(qpath, expr, call_expr_and_args),
_ => self.check_expr_kind(expr, expected),
});
let ty = self.resolve_vars_if_possible(ty);
Expand Down Expand Up @@ -452,28 +461,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

let tcx = self.tcx;
match expr.kind {
ExprKind::Lit(ref lit) => self.check_lit(lit, expected),
ExprKind::Binary(op, lhs, rhs) => self.check_binop(expr, op, lhs, rhs, expected),
ExprKind::Lit(ref lit) => self.check_expr_lit(lit, expected),
ExprKind::Binary(op, lhs, rhs) => self.check_expr_binop(expr, op, lhs, rhs, expected),
ExprKind::Assign(lhs, rhs, span) => {
self.check_expr_assign(expr, expected, lhs, rhs, span)
}
ExprKind::AssignOp(op, lhs, rhs) => {
self.check_binop_assign(expr, op, lhs, rhs, expected)
self.check_expr_binop_assign(expr, op, lhs, rhs, expected)
}
ExprKind::Unary(unop, oprnd) => self.check_expr_unary(unop, oprnd, expected, expr),
ExprKind::Unary(unop, oprnd) => self.check_expr_unop(unop, oprnd, expected, expr),
ExprKind::AddrOf(kind, mutbl, oprnd) => {
self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
}
ExprKind::Path(QPath::LangItem(lang_item, _)) => {
self.check_lang_item_path(lang_item, expr)
}
ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, None, None),
ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, None),
ExprKind::InlineAsm(asm) => {
// We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars).
self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id));
self.check_expr_asm(asm)
}
ExprKind::OffsetOf(container, fields) => self.check_offset_of(container, fields, expr),
ExprKind::OffsetOf(container, fields) => {
self.check_expr_offset_of(container, fields, expr)
}
ExprKind::Break(destination, ref expr_opt) => {
self.check_expr_break(destination, expr_opt.as_deref(), expr)
}
Expand All @@ -492,13 +503,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_expr_loop(body, source, expected, expr)
}
ExprKind::Match(discrim, arms, match_src) => {
self.check_match(expr, discrim, arms, expected, match_src)
self.check_expr_match(expr, discrim, arms, expected, match_src)
}
ExprKind::Closure(closure) => self.check_expr_closure(closure, expr.span, expected),
ExprKind::Block(body, _) => self.check_block_with_expected(body, expected),
ExprKind::Call(callee, args) => self.check_call(expr, callee, args, expected),
ExprKind::Block(body, _) => self.check_expr_block(body, expected),
ExprKind::Call(callee, args) => self.check_expr_call(expr, callee, args, expected),
ExprKind::MethodCall(segment, receiver, args, _) => {
self.check_method_call(expr, segment, receiver, args, expected)
self.check_expr_method_call(expr, segment, receiver, args, expected)
}
ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr),
ExprKind::Type(e, t) => {
Expand All @@ -508,7 +519,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ascribed_ty
}
ExprKind::If(cond, then_expr, opt_else_expr) => {
self.check_then_else(cond, then_expr, opt_else_expr, expr.span, expected)
self.check_expr_if(cond, then_expr, opt_else_expr, expr.span, expected)
}
ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
Expand All @@ -520,7 +531,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ExprKind::Struct(qpath, fields, ref base_expr) => {
self.check_expr_struct(expr, expected, qpath, fields, base_expr)
}
ExprKind::Field(base, field) => self.check_field(expr, base, field, expected),
ExprKind::Field(base, field) => self.check_expr_field(expr, base, field, expected),
ExprKind::Index(base, idx, brackets_span) => {
self.check_expr_index(base, idx, expr, brackets_span)
}
Expand All @@ -529,7 +540,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

fn check_expr_unary(
fn check_expr_unop(
&self,
unop: hir::UnOp,
oprnd: &'tcx hir::Expr<'tcx>,
Expand Down Expand Up @@ -679,8 +690,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
qpath: &'tcx hir::QPath<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
args: Option<&'tcx [hir::Expr<'tcx>]>,
call: Option<&'tcx hir::Expr<'tcx>>,
call_expr_and_args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
) -> Ty<'tcx> {
let tcx = self.tcx;
let (res, opt_ty, segs) =
Expand Down Expand Up @@ -710,7 +720,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
segs,
opt_ty,
res,
call.map_or(expr.span, |e| e.span),
call_expr_and_args.map_or(expr.span, |(e, _)| e.span),
expr.span,
expr.hir_id,
)
Expand Down Expand Up @@ -749,7 +759,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We just want to check sizedness, so instead of introducing
// placeholder lifetimes with probing, we just replace higher lifetimes
// with fresh vars.
let span = args.and_then(|args| args.get(i)).map_or(expr.span, |arg| arg.span);
let span = call_expr_and_args
.and_then(|(_, args)| args.get(i))
.map_or(expr.span, |arg| arg.span);
let input = self.instantiate_binder_with_fresh_vars(
span,
infer::BoundRegionConversionTime::FnCall,
Expand All @@ -775,7 +787,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
self.require_type_is_sized_deferred(
output,
call.map_or(expr.span, |e| e.span),
call_expr_and_args.map_or(expr.span, |(e, _)| e.span),
ObligationCauseCode::SizedCallReturnType,
);
}
Expand Down Expand Up @@ -952,7 +964,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self.ret_coercion_span.get().is_none() {
self.ret_coercion_span.set(Some(e.span));
}
self.check_return_expr(e, true);
self.check_return_or_body_tail(e, true);
} else {
let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
if self.ret_coercion_span.get().is_none() {
Expand Down Expand Up @@ -1015,7 +1027,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
///
/// `explicit_return` is `true` if we're checking an explicit `return expr`,
/// and `false` if we're checking a trailing expression.
pub(super) fn check_return_expr(
pub(super) fn check_return_or_body_tail(
&self,
return_expr: &'tcx hir::Expr<'tcx>,
explicit_return: bool,
Expand Down Expand Up @@ -1239,7 +1251,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

// A generic function for checking the 'then' and 'else' clauses in an 'if'
// or 'if-else' expression.
fn check_then_else(
fn check_expr_if(
&self,
cond_expr: &'tcx hir::Expr<'tcx>,
then_expr: &'tcx hir::Expr<'tcx>,
Expand Down Expand Up @@ -1522,7 +1534,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

/// Checks a method call.
fn check_method_call(
fn check_expr_method_call(
&self,
expr: &'tcx hir::Expr<'tcx>,
segment: &'tcx hir::PathSegment<'tcx>,
Expand Down Expand Up @@ -2574,7 +2586,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

// Check field access expressions
fn check_field(
fn check_expr_field(
&self,
expr: &'tcx hir::Expr<'tcx>,
base: &'tcx hir::Expr<'tcx>,
Expand Down Expand Up @@ -3515,8 +3527,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let previous_diverges = self.diverges.get();

// The label blocks should have unit return value or diverge.
let ty =
self.check_block_with_expected(block, ExpectHasType(self.tcx.types.unit));
let ty = self.check_expr_block(block, ExpectHasType(self.tcx.types.unit));
if !ty.is_never() {
self.demand_suptype(block.span, self.tcx.types.unit, ty);
diverge = false;
Expand All @@ -3531,7 +3542,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if diverge { self.tcx.types.never } else { self.tcx.types.unit }
}

fn check_offset_of(
fn check_expr_offset_of(
&self,
container: &'tcx hir::Ty<'tcx>,
fields: &[Ident],
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1565,7 +1565,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

// AST fragment checking
pub(in super::super) fn check_lit(
pub(in super::super) fn check_expr_lit(
&self,
lit: &hir::Lit,
expected: Expectation<'tcx>,
Expand Down Expand Up @@ -1747,7 +1747,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

if let Some(blk) = decl.origin.try_get_else() {
let previous_diverges = self.diverges.get();
let else_ty = self.check_block_with_expected(blk, NoExpectation);
let else_ty = self.check_expr_block(blk, NoExpectation);
let cause = self.cause(blk.span, ObligationCauseCode::LetElse);
if let Err(err) = self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty)
{
Expand Down Expand Up @@ -1805,7 +1805,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

pub(crate) fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) {
let unit = self.tcx.types.unit;
let ty = self.check_block_with_expected(blk, ExpectHasType(unit));
let ty = self.check_expr_block(blk, ExpectHasType(unit));

// if the block produces a `!` value, that can always be
// (effectively) coerced to unit.
Expand All @@ -1814,7 +1814,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

pub(in super::super) fn check_block_with_expected(
pub(in super::super) fn check_expr_block(
&self,
blk: &'tcx hir::Block<'tcx>,
expected: Expectation<'tcx>,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::Expectation;

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Checks a `a <op>= b`
pub(crate) fn check_binop_assign(
pub(crate) fn check_expr_binop_assign(
&self,
expr: &'tcx hir::Expr<'tcx>,
op: hir::BinOp,
Expand Down Expand Up @@ -85,7 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

/// Checks a potentially overloaded binary operator.
pub(crate) fn check_binop(
pub(crate) fn check_expr_binop(
&self,
expr: &'tcx hir::Expr<'tcx>,
op: hir::BinOp,
Expand Down
Loading