rustc_hir_typeck: fix paths and partially mv files
This commit is contained in:
parent
f468a90bad
commit
fb3ab13a1c
39 changed files with 1232 additions and 1133 deletions
27
Cargo.lock
27
Cargo.lock
|
@ -3568,6 +3568,32 @@ dependencies = [
|
||||||
"rustc_target",
|
"rustc_target",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_hir_typeck"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"rustc_ast",
|
||||||
|
"rustc_data_structures",
|
||||||
|
"rustc_errors",
|
||||||
|
"rustc_graphviz",
|
||||||
|
"rustc_hir",
|
||||||
|
"rustc_hir_analysis",
|
||||||
|
"rustc_hir_pretty",
|
||||||
|
"rustc_index",
|
||||||
|
"rustc_infer",
|
||||||
|
"rustc_lint",
|
||||||
|
"rustc_macros",
|
||||||
|
"rustc_middle",
|
||||||
|
"rustc_serialize",
|
||||||
|
"rustc_session",
|
||||||
|
"rustc_span",
|
||||||
|
"rustc_target",
|
||||||
|
"rustc_trait_selection",
|
||||||
|
"rustc_type_ir",
|
||||||
|
"smallvec",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_incremental"
|
name = "rustc_incremental"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -3637,6 +3663,7 @@ dependencies = [
|
||||||
"rustc_expand",
|
"rustc_expand",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_hir_analysis",
|
"rustc_hir_analysis",
|
||||||
|
"rustc_hir_typeck",
|
||||||
"rustc_incremental",
|
"rustc_incremental",
|
||||||
"rustc_lint",
|
"rustc_lint",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
|
|
|
@ -582,7 +582,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
assoc_bindings
|
assoc_bindings
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn create_substs_for_associated_item(
|
pub fn create_substs_for_associated_item(
|
||||||
&self,
|
&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
item_def_id: DefId,
|
item_def_id: DefId,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::check::intrinsicck::InlineAsmCtxt;
|
use crate::check::intrinsicck::InlineAsmCtxt;
|
||||||
|
|
||||||
use super::coercion::CoerceMany;
|
|
||||||
use super::compare_method::check_type_bounds;
|
use super::compare_method::check_type_bounds;
|
||||||
use super::compare_method::{compare_impl_method, compare_ty_impl};
|
use super::compare_method::{compare_impl_method, compare_ty_impl};
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -10,10 +9,8 @@ use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::Visitor;
|
||||||
use rustc_hir::lang_items::LangItem;
|
|
||||||
use rustc_hir::{ItemKind, Node, PathSegment};
|
use rustc_hir::{ItemKind, Node, PathSegment};
|
||||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
|
||||||
use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
|
use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::Obligation;
|
use rustc_infer::traits::Obligation;
|
||||||
use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
|
use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
|
||||||
|
@ -34,7 +31,7 @@ use rustc_trait_selection::traits::{self, ObligationCtxt};
|
||||||
|
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
|
pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
|
||||||
match tcx.sess.target.is_abi_supported(abi) {
|
match tcx.sess.target.is_abi_supported(abi) {
|
||||||
Some(true) => (),
|
Some(true) => (),
|
||||||
Some(false) => {
|
Some(false) => {
|
||||||
|
@ -69,313 +66,6 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper used for fns and closures. Does the grungy work of checking a function
|
|
||||||
/// body and returns the function context used for that purpose, since in the case of a fn item
|
|
||||||
/// there is still a bit more to do.
|
|
||||||
///
|
|
||||||
/// * ...
|
|
||||||
/// * inherited: other fields inherited from the enclosing fn (if any)
|
|
||||||
#[instrument(skip(inherited, body), level = "debug")]
|
|
||||||
pub(super) fn check_fn<'a, 'tcx>(
|
|
||||||
inherited: &'a Inherited<'tcx>,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
fn_sig: ty::FnSig<'tcx>,
|
|
||||||
decl: &'tcx hir::FnDecl<'tcx>,
|
|
||||||
fn_id: hir::HirId,
|
|
||||||
body: &'tcx hir::Body<'tcx>,
|
|
||||||
can_be_generator: Option<hir::Movability>,
|
|
||||||
return_type_pre_known: bool,
|
|
||||||
) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
|
|
||||||
// Create the function context. This is either derived from scratch or,
|
|
||||||
// in the case of closures, based on the outer context.
|
|
||||||
let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
|
|
||||||
fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
|
|
||||||
fcx.return_type_pre_known = return_type_pre_known;
|
|
||||||
|
|
||||||
let tcx = fcx.tcx;
|
|
||||||
let hir = tcx.hir();
|
|
||||||
|
|
||||||
let declared_ret_ty = fn_sig.output();
|
|
||||||
|
|
||||||
let ret_ty =
|
|
||||||
fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
|
|
||||||
declared_ret_ty,
|
|
||||||
body.value.hir_id,
|
|
||||||
decl.output.span(),
|
|
||||||
param_env,
|
|
||||||
));
|
|
||||||
// If we replaced declared_ret_ty with infer vars, then we must be inferring
|
|
||||||
// an opaque type, so set a flag so we can improve diagnostics.
|
|
||||||
fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
|
|
||||||
|
|
||||||
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
|
|
||||||
|
|
||||||
let span = body.value.span;
|
|
||||||
|
|
||||||
fn_maybe_err(tcx, span, fn_sig.abi);
|
|
||||||
|
|
||||||
if fn_sig.abi == Abi::RustCall {
|
|
||||||
let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
|
|
||||||
|
|
||||||
let err = || {
|
|
||||||
let item = match tcx.hir().get(fn_id) {
|
|
||||||
Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
|
|
||||||
Node::ImplItem(hir::ImplItem {
|
|
||||||
kind: hir::ImplItemKind::Fn(header, ..), ..
|
|
||||||
}) => Some(header),
|
|
||||||
Node::TraitItem(hir::TraitItem {
|
|
||||||
kind: hir::TraitItemKind::Fn(header, ..),
|
|
||||||
..
|
|
||||||
}) => Some(header),
|
|
||||||
// Closures are RustCall, but they tuple their arguments, so shouldn't be checked
|
|
||||||
Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None,
|
|
||||||
node => bug!("Item being checked wasn't a function/closure: {:?}", node),
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(header) = item {
|
|
||||||
tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if fn_sig.inputs().len() != expected_args {
|
|
||||||
err()
|
|
||||||
} else {
|
|
||||||
// FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
|
|
||||||
// This will probably require wide-scale changes to support a TupleKind obligation
|
|
||||||
// We can't resolve this without knowing the type of the param
|
|
||||||
if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
|
|
||||||
err()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if body.generator_kind.is_some() && can_be_generator.is_some() {
|
|
||||||
let yield_ty = fcx
|
|
||||||
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
|
|
||||||
fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
|
|
||||||
|
|
||||||
// Resume type defaults to `()` if the generator has no argument.
|
|
||||||
let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
|
|
||||||
|
|
||||||
fcx.resume_yield_tys = Some((resume_ty, yield_ty));
|
|
||||||
}
|
|
||||||
|
|
||||||
GatherLocalsVisitor::new(&fcx).visit_body(body);
|
|
||||||
|
|
||||||
// C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
|
|
||||||
// (as it's created inside the body itself, not passed in from outside).
|
|
||||||
let maybe_va_list = if fn_sig.c_variadic {
|
|
||||||
let span = body.params.last().unwrap().span;
|
|
||||||
let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
|
|
||||||
let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
|
|
||||||
|
|
||||||
Some(tcx.bound_type_of(va_list_did).subst(tcx, &[region.into()]))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add formal parameters.
|
|
||||||
let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
|
|
||||||
let inputs_fn = fn_sig.inputs().iter().copied();
|
|
||||||
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
|
|
||||||
// Check the pattern.
|
|
||||||
let ty_span = try { inputs_hir?.get(idx)?.span };
|
|
||||||
fcx.check_pat_top(¶m.pat, param_ty, ty_span, false);
|
|
||||||
|
|
||||||
// Check that argument is Sized.
|
|
||||||
// The check for a non-trivial pattern is a hack to avoid duplicate warnings
|
|
||||||
// for simple cases like `fn foo(x: Trait)`,
|
|
||||||
// where we would error once on the parameter as a whole, and once on the binding `x`.
|
|
||||||
if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params {
|
|
||||||
fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
|
|
||||||
}
|
|
||||||
|
|
||||||
fcx.write_ty(param.hir_id, param_ty);
|
|
||||||
}
|
|
||||||
|
|
||||||
inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
|
|
||||||
|
|
||||||
fcx.in_tail_expr = true;
|
|
||||||
if let ty::Dynamic(..) = declared_ret_ty.kind() {
|
|
||||||
// FIXME: We need to verify that the return type is `Sized` after the return expression has
|
|
||||||
// been evaluated so that we have types available for all the nodes being returned, but that
|
|
||||||
// requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
|
|
||||||
// causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
|
|
||||||
// while keeping the current ordering we will ignore the tail expression's type because we
|
|
||||||
// don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
|
|
||||||
// because we will trigger "unreachable expression" lints unconditionally.
|
|
||||||
// Because of all of this, we perform a crude check to know whether the simplest `!Sized`
|
|
||||||
// case that a newcomer might make, returning a bare trait, and in that case we populate
|
|
||||||
// the tail expression's type so that the suggestion will be correct, but ignore all other
|
|
||||||
// possible cases.
|
|
||||||
fcx.check_expr(&body.value);
|
|
||||||
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
|
|
||||||
} else {
|
|
||||||
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
|
|
||||||
fcx.check_return_expr(&body.value, false);
|
|
||||||
}
|
|
||||||
fcx.in_tail_expr = false;
|
|
||||||
|
|
||||||
// We insert the deferred_generator_interiors entry after visiting the body.
|
|
||||||
// This ensures that all nested generators appear before the entry of this generator.
|
|
||||||
// resolve_generator_interiors relies on this property.
|
|
||||||
let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
|
|
||||||
let interior = fcx
|
|
||||||
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
|
|
||||||
fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
|
|
||||||
|
|
||||||
let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
|
|
||||||
Some(GeneratorTypes {
|
|
||||||
resume_ty,
|
|
||||||
yield_ty,
|
|
||||||
interior,
|
|
||||||
movability: can_be_generator.unwrap(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// really expected to fail, since the coercions would have failed
|
|
||||||
// earlier when trying to find a LUB.
|
|
||||||
let coercion = fcx.ret_coercion.take().unwrap().into_inner();
|
|
||||||
let mut actual_return_ty = coercion.complete(&fcx);
|
|
||||||
debug!("actual_return_ty = {:?}", actual_return_ty);
|
|
||||||
if let ty::Dynamic(..) = declared_ret_ty.kind() {
|
|
||||||
// We have special-cased the case where the function is declared
|
|
||||||
// `-> dyn Foo` and we don't actually relate it to the
|
|
||||||
// `fcx.ret_coercion`, so just substitute a type variable.
|
|
||||||
actual_return_ty =
|
|
||||||
fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
|
|
||||||
debug!("actual_return_ty replaced with {:?}", actual_return_ty);
|
|
||||||
}
|
|
||||||
|
|
||||||
// HACK(oli-obk, compiler-errors): We should be comparing this against
|
|
||||||
// `declared_ret_ty`, but then anything uninferred would be inferred to
|
|
||||||
// the opaque type itself. That again would cause writeback to assume
|
|
||||||
// we have a recursive call site and do the sadly stabilized fallback to `()`.
|
|
||||||
fcx.demand_suptype(span, ret_ty, actual_return_ty);
|
|
||||||
|
|
||||||
// Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
|
|
||||||
if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
|
|
||||||
&& panic_impl_did == hir.local_def_id(fn_id).to_def_id()
|
|
||||||
{
|
|
||||||
check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
|
|
||||||
if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
|
|
||||||
&& alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
|
|
||||||
{
|
|
||||||
check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
|
|
||||||
}
|
|
||||||
|
|
||||||
(fcx, gen_ty)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_panic_info_fn(
|
|
||||||
tcx: TyCtxt<'_>,
|
|
||||||
fn_id: LocalDefId,
|
|
||||||
fn_sig: ty::FnSig<'_>,
|
|
||||||
decl: &hir::FnDecl<'_>,
|
|
||||||
declared_ret_ty: Ty<'_>,
|
|
||||||
) {
|
|
||||||
let Some(panic_info_did) = tcx.lang_items().panic_info() else {
|
|
||||||
tcx.sess.err("language item required, but not found: `panic_info`");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
if *declared_ret_ty.kind() != ty::Never {
|
|
||||||
tcx.sess.span_err(decl.output.span(), "return type should be `!`");
|
|
||||||
}
|
|
||||||
|
|
||||||
let inputs = fn_sig.inputs();
|
|
||||||
if inputs.len() != 1 {
|
|
||||||
tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let arg_is_panic_info = match *inputs[0].kind() {
|
|
||||||
ty::Ref(region, ty, mutbl) => match *ty.kind() {
|
|
||||||
ty::Adt(ref adt, _) => {
|
|
||||||
adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if !arg_is_panic_info {
|
|
||||||
tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
|
|
||||||
}
|
|
||||||
|
|
||||||
let DefKind::Fn = tcx.def_kind(fn_id) else {
|
|
||||||
let span = tcx.def_span(fn_id);
|
|
||||||
tcx.sess.span_err(span, "should be a function");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let generic_counts = tcx.generics_of(fn_id).own_counts();
|
|
||||||
if generic_counts.types != 0 {
|
|
||||||
let span = tcx.def_span(fn_id);
|
|
||||||
tcx.sess.span_err(span, "should have no type parameters");
|
|
||||||
}
|
|
||||||
if generic_counts.consts != 0 {
|
|
||||||
let span = tcx.def_span(fn_id);
|
|
||||||
tcx.sess.span_err(span, "should have no const parameters");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_alloc_error_fn(
|
|
||||||
tcx: TyCtxt<'_>,
|
|
||||||
fn_id: LocalDefId,
|
|
||||||
fn_sig: ty::FnSig<'_>,
|
|
||||||
decl: &hir::FnDecl<'_>,
|
|
||||||
declared_ret_ty: Ty<'_>,
|
|
||||||
) {
|
|
||||||
let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
|
|
||||||
tcx.sess.err("language item required, but not found: `alloc_layout`");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
if *declared_ret_ty.kind() != ty::Never {
|
|
||||||
tcx.sess.span_err(decl.output.span(), "return type should be `!`");
|
|
||||||
}
|
|
||||||
|
|
||||||
let inputs = fn_sig.inputs();
|
|
||||||
if inputs.len() != 1 {
|
|
||||||
tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let arg_is_alloc_layout = match inputs[0].kind() {
|
|
||||||
ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if !arg_is_alloc_layout {
|
|
||||||
tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
|
|
||||||
}
|
|
||||||
|
|
||||||
let DefKind::Fn = tcx.def_kind(fn_id) else {
|
|
||||||
let span = tcx.def_span(fn_id);
|
|
||||||
tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let generic_counts = tcx.generics_of(fn_id).own_counts();
|
|
||||||
if generic_counts.types != 0 {
|
|
||||||
let span = tcx.def_span(fn_id);
|
|
||||||
tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
|
|
||||||
}
|
|
||||||
if generic_counts.consts != 0 {
|
|
||||||
let span = tcx.def_span(fn_id);
|
|
||||||
tcx.sess
|
|
||||||
.span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||||
let def = tcx.adt_def(def_id);
|
let def = tcx.adt_def(def_id);
|
||||||
let span = tcx.def_span(def_id);
|
let span = tcx.def_span(def_id);
|
||||||
|
|
|
@ -1,117 +1,11 @@
|
||||||
use hir::HirId;
|
|
||||||
use rustc_ast::InlineAsmTemplatePiece;
|
use rustc_ast::InlineAsmTemplatePiece;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::struct_span_err;
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_index::vec::Idx;
|
|
||||||
use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
|
|
||||||
use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy};
|
use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_span::{Symbol, DUMMY_SP};
|
use rustc_span::{Symbol, DUMMY_SP};
|
||||||
use rustc_target::abi::{Pointer, VariantIdx};
|
|
||||||
use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType};
|
use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType};
|
||||||
|
|
||||||
use super::FnCtxt;
|
|
||||||
|
|
||||||
/// If the type is `Option<T>`, it will return `T`, otherwise
|
|
||||||
/// the type itself. Works on most `Option`-like types.
|
|
||||||
fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
|
|
||||||
let ty::Adt(def, substs) = *ty.kind() else { return ty };
|
|
||||||
|
|
||||||
if def.variants().len() == 2 && !def.repr().c() && def.repr().int.is_none() {
|
|
||||||
let data_idx;
|
|
||||||
|
|
||||||
let one = VariantIdx::new(1);
|
|
||||||
let zero = VariantIdx::new(0);
|
|
||||||
|
|
||||||
if def.variant(zero).fields.is_empty() {
|
|
||||||
data_idx = one;
|
|
||||||
} else if def.variant(one).fields.is_empty() {
|
|
||||||
data_idx = zero;
|
|
||||||
} else {
|
|
||||||
return ty;
|
|
||||||
}
|
|
||||||
|
|
||||||
if def.variant(data_idx).fields.len() == 1 {
|
|
||||||
return def.variant(data_idx).fields[0].ty(tcx, substs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ty
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|
||||||
pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
|
|
||||||
let tcx = self.tcx;
|
|
||||||
let span = tcx.hir().span(hir_id);
|
|
||||||
let normalize = |ty| {
|
|
||||||
let ty = self.resolve_vars_if_possible(ty);
|
|
||||||
self.tcx.normalize_erasing_regions(self.param_env, ty)
|
|
||||||
};
|
|
||||||
let from = normalize(from);
|
|
||||||
let to = normalize(to);
|
|
||||||
trace!(?from, ?to);
|
|
||||||
|
|
||||||
// Transmutes that are only changing lifetimes are always ok.
|
|
||||||
if from == to {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let skel = |ty| SizeSkeleton::compute(ty, tcx, self.param_env);
|
|
||||||
let sk_from = skel(from);
|
|
||||||
let sk_to = skel(to);
|
|
||||||
trace!(?sk_from, ?sk_to);
|
|
||||||
|
|
||||||
// Check for same size using the skeletons.
|
|
||||||
if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
|
|
||||||
if sk_from.same_size(sk_to) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special-case transmuting from `typeof(function)` and
|
|
||||||
// `Option<typeof(function)>` to present a clearer error.
|
|
||||||
let from = unpack_option_like(tcx, from);
|
|
||||||
if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&tcx) {
|
|
||||||
struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
|
|
||||||
.note(&format!("source type: {from}"))
|
|
||||||
.note(&format!("target type: {to}"))
|
|
||||||
.help("cast with `as` to a pointer instead")
|
|
||||||
.emit();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to display a sensible error with as much information as possible.
|
|
||||||
let skeleton_string = |ty: Ty<'tcx>, sk| match sk {
|
|
||||||
Ok(SizeSkeleton::Known(size)) => format!("{} bits", size.bits()),
|
|
||||||
Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
|
|
||||||
Err(LayoutError::Unknown(bad)) => {
|
|
||||||
if bad == ty {
|
|
||||||
"this type does not have a fixed size".to_owned()
|
|
||||||
} else {
|
|
||||||
format!("size can vary because of {bad}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => err.to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut err = struct_span_err!(
|
|
||||||
tcx.sess,
|
|
||||||
span,
|
|
||||||
E0512,
|
|
||||||
"cannot transmute between types of different sizes, \
|
|
||||||
or dependently-sized types"
|
|
||||||
);
|
|
||||||
if from == to {
|
|
||||||
err.note(&format!("`{from}` does not have a fixed size"));
|
|
||||||
} else {
|
|
||||||
err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
|
|
||||||
.note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
|
|
||||||
}
|
|
||||||
err.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct InlineAsmCtxt<'a, 'tcx> {
|
pub struct InlineAsmCtxt<'a, 'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
|
|
@ -62,191 +62,45 @@ a type parameter).
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub mod _match;
|
|
||||||
mod autoderef;
|
|
||||||
mod callee;
|
|
||||||
pub mod cast;
|
|
||||||
mod check;
|
mod check;
|
||||||
mod closure;
|
|
||||||
pub mod coercion;
|
|
||||||
mod compare_method;
|
mod compare_method;
|
||||||
pub mod demand;
|
|
||||||
mod diverges;
|
|
||||||
pub mod dropck;
|
pub mod dropck;
|
||||||
mod expectation;
|
|
||||||
mod expr;
|
|
||||||
mod fallback;
|
|
||||||
mod fn_ctxt;
|
|
||||||
mod gather_locals;
|
|
||||||
mod generator_interior;
|
|
||||||
mod inherited;
|
|
||||||
pub mod intrinsic;
|
pub mod intrinsic;
|
||||||
mod intrinsicck;
|
pub mod intrinsicck;
|
||||||
pub mod method;
|
|
||||||
mod op;
|
|
||||||
mod pat;
|
|
||||||
mod place_op;
|
|
||||||
mod region;
|
mod region;
|
||||||
pub mod rvalue_scopes;
|
|
||||||
mod upvar;
|
|
||||||
pub mod wfcheck;
|
pub mod wfcheck;
|
||||||
pub mod writeback;
|
|
||||||
|
|
||||||
use check::{check_abi, check_fn, check_mod_item_types};
|
pub use check::check_abi;
|
||||||
pub use diverges::Diverges;
|
|
||||||
pub use expectation::Expectation;
|
|
||||||
pub use fn_ctxt::*;
|
|
||||||
pub use inherited::{Inherited, InheritedBuilder};
|
|
||||||
|
|
||||||
use crate::astconv::AstConv;
|
use check::check_mod_item_types;
|
||||||
use crate::check::gather_locals::GatherLocalsVisitor;
|
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_errors::{
|
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder};
|
||||||
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan,
|
|
||||||
};
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::Res;
|
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::Visitor;
|
||||||
use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
|
|
||||||
use rustc_index::bit_set::BitSet;
|
use rustc_index::bit_set::BitSet;
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt, UserType};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_middle::ty::{InternalSubsts, SubstsRef};
|
use rustc_middle::ty::{InternalSubsts, SubstsRef};
|
||||||
use rustc_session::config;
|
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_session::Session;
|
|
||||||
use rustc_span::source_map::DUMMY_SP;
|
use rustc_span::source_map::DUMMY_SP;
|
||||||
use rustc_span::symbol::{kw, Ident};
|
use rustc_span::symbol::{kw, Ident};
|
||||||
use rustc_span::{self, BytePos, Span, Symbol};
|
use rustc_span::{self, BytePos, Span, Symbol};
|
||||||
use rustc_target::abi::VariantIdx;
|
use rustc_target::abi::VariantIdx;
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use rustc_trait_selection::traits;
|
|
||||||
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
|
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
|
|
||||||
use crate::require_c_abi_if_c_variadic;
|
use crate::require_c_abi_if_c_variadic;
|
||||||
use crate::util::common::indenter;
|
use crate::util::common::indenter;
|
||||||
|
|
||||||
use self::coercion::DynamicCoerceMany;
|
|
||||||
use self::compare_method::collect_trait_impl_trait_tys;
|
use self::compare_method::collect_trait_impl_trait_tys;
|
||||||
use self::region::region_scope_tree;
|
use self::region::region_scope_tree;
|
||||||
pub use self::Expectation::*;
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! type_error_struct {
|
|
||||||
($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
|
|
||||||
let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
|
|
||||||
|
|
||||||
if $typ.references_error() {
|
|
||||||
err.downgrade_to_delayed_bug();
|
|
||||||
}
|
|
||||||
|
|
||||||
err
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The type of a local binding, including the revealed type for anon types.
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub struct LocalTy<'tcx> {
|
|
||||||
decl_ty: Ty<'tcx>,
|
|
||||||
revealed_ty: Ty<'tcx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub enum Needs {
|
|
||||||
MutPlace,
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Needs {
|
|
||||||
fn maybe_mut_place(m: hir::Mutability) -> Self {
|
|
||||||
match m {
|
|
||||||
hir::Mutability::Mut => Needs::MutPlace,
|
|
||||||
hir::Mutability::Not => Needs::None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct UnsafetyState {
|
|
||||||
pub def: hir::HirId,
|
|
||||||
pub unsafety: hir::Unsafety,
|
|
||||||
from_fn: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UnsafetyState {
|
|
||||||
pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
|
|
||||||
UnsafetyState { def, unsafety, from_fn: true }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
|
|
||||||
use hir::BlockCheckMode;
|
|
||||||
match self.unsafety {
|
|
||||||
// If this unsafe, then if the outer function was already marked as
|
|
||||||
// unsafe we shouldn't attribute the unsafe'ness to the block. This
|
|
||||||
// way the block can be warned about instead of ignoring this
|
|
||||||
// extraneous block (functions are never warned about).
|
|
||||||
hir::Unsafety::Unsafe if self.from_fn => self,
|
|
||||||
|
|
||||||
unsafety => {
|
|
||||||
let (unsafety, def) = match blk.rules {
|
|
||||||
BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
|
|
||||||
BlockCheckMode::DefaultBlock => (unsafety, self.def),
|
|
||||||
};
|
|
||||||
UnsafetyState { def, unsafety, from_fn: false }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub enum PlaceOp {
|
|
||||||
Deref,
|
|
||||||
Index,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BreakableCtxt<'tcx> {
|
|
||||||
may_break: bool,
|
|
||||||
|
|
||||||
// this is `null` for loops where break with a value is illegal,
|
|
||||||
// such as `while`, `for`, and `while let`
|
|
||||||
coerce: Option<DynamicCoerceMany<'tcx>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct EnclosingBreakables<'tcx> {
|
|
||||||
stack: Vec<BreakableCtxt<'tcx>>,
|
|
||||||
by_id: HirIdMap<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> EnclosingBreakables<'tcx> {
|
|
||||||
fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
|
|
||||||
self.opt_find_breakable(target_id).unwrap_or_else(|| {
|
|
||||||
bug!("could not find enclosing breakable with id {}", target_id);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
|
|
||||||
match self.by_id.get(&target_id) {
|
|
||||||
Some(ix) => Some(&mut self.stack[*ix]),
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
method::provide(providers);
|
|
||||||
wfcheck::provide(providers);
|
wfcheck::provide(providers);
|
||||||
*providers = Providers {
|
*providers = Providers {
|
||||||
typeck_item_bodies,
|
|
||||||
typeck_const_arg,
|
|
||||||
typeck,
|
|
||||||
diagnostic_only_typeck,
|
|
||||||
has_typeck_results,
|
|
||||||
adt_destructor,
|
adt_destructor,
|
||||||
used_trait_imports,
|
|
||||||
check_mod_item_types,
|
check_mod_item_types,
|
||||||
region_scope_tree,
|
region_scope_tree,
|
||||||
collect_trait_impl_trait_tys,
|
collect_trait_impl_trait_tys,
|
||||||
|
@ -259,259 +113,6 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
|
||||||
tcx.calculate_dtor(def_id, dropck::check_drop_impl)
|
tcx.calculate_dtor(def_id, dropck::check_drop_impl)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If this `DefId` is a "primary tables entry", returns
|
|
||||||
/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
|
|
||||||
///
|
|
||||||
/// If this function returns `Some`, then `typeck_results(def_id)` will
|
|
||||||
/// succeed; if it returns `None`, then `typeck_results(def_id)` may or
|
|
||||||
/// may not succeed. In some cases where this function returns `None`
|
|
||||||
/// (notably closures), `typeck_results(def_id)` would wind up
|
|
||||||
/// redirecting to the owning function.
|
|
||||||
fn primary_body_of(
|
|
||||||
tcx: TyCtxt<'_>,
|
|
||||||
id: hir::HirId,
|
|
||||||
) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
|
|
||||||
match tcx.hir().get(id) {
|
|
||||||
Node::Item(item) => match item.kind {
|
|
||||||
hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
|
|
||||||
Some((body, Some(ty), None))
|
|
||||||
}
|
|
||||||
hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
Node::TraitItem(item) => match item.kind {
|
|
||||||
hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
|
|
||||||
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
|
|
||||||
Some((body, None, Some(sig)))
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
Node::ImplItem(item) => match item.kind {
|
|
||||||
hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
|
|
||||||
hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
Node::AnonConst(constant) => Some((constant.body, None, None)),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
|
||||||
// Closures' typeck results come from their outermost function,
|
|
||||||
// as they are part of the same "inference environment".
|
|
||||||
let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
|
|
||||||
if typeck_root_def_id != def_id {
|
|
||||||
return tcx.has_typeck_results(typeck_root_def_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(def_id) = def_id.as_local() {
|
|
||||||
let id = tcx.hir().local_def_id_to_hir_id(def_id);
|
|
||||||
primary_body_of(tcx, id).is_some()
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
|
|
||||||
&*tcx.typeck(def_id).used_trait_imports
|
|
||||||
}
|
|
||||||
|
|
||||||
fn typeck_const_arg<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
(did, param_did): (LocalDefId, DefId),
|
|
||||||
) -> &ty::TypeckResults<'tcx> {
|
|
||||||
let fallback = move || tcx.type_of(param_did);
|
|
||||||
typeck_with_fallback(tcx, did, fallback)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
|
|
||||||
if let Some(param_did) = tcx.opt_const_param_of(def_id) {
|
|
||||||
tcx.typeck_const_arg((def_id, param_did))
|
|
||||||
} else {
|
|
||||||
let fallback = move || tcx.type_of(def_id.to_def_id());
|
|
||||||
typeck_with_fallback(tcx, def_id, fallback)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used only to get `TypeckResults` for type inference during error recovery.
|
|
||||||
/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
|
|
||||||
fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
|
|
||||||
let fallback = move || {
|
|
||||||
let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
|
|
||||||
tcx.ty_error_with_message(span, "diagnostic only typeck table used")
|
|
||||||
};
|
|
||||||
typeck_with_fallback(tcx, def_id, fallback)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn typeck_with_fallback<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
def_id: LocalDefId,
|
|
||||||
fallback: impl Fn() -> Ty<'tcx> + 'tcx,
|
|
||||||
) -> &'tcx ty::TypeckResults<'tcx> {
|
|
||||||
// Closures' typeck results come from their outermost function,
|
|
||||||
// as they are part of the same "inference environment".
|
|
||||||
let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
|
|
||||||
if typeck_root_def_id != def_id {
|
|
||||||
return tcx.typeck(typeck_root_def_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
let id = tcx.hir().local_def_id_to_hir_id(def_id);
|
|
||||||
let span = tcx.hir().span(id);
|
|
||||||
|
|
||||||
// Figure out what primary body this item has.
|
|
||||||
let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
|
|
||||||
span_bug!(span, "can't type-check body of {:?}", def_id);
|
|
||||||
});
|
|
||||||
let body = tcx.hir().body(body_id);
|
|
||||||
|
|
||||||
let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
|
|
||||||
let param_env = tcx.param_env(def_id);
|
|
||||||
let mut fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
|
|
||||||
let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
|
|
||||||
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
|
|
||||||
<dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
|
|
||||||
} else {
|
|
||||||
tcx.fn_sig(def_id)
|
|
||||||
};
|
|
||||||
|
|
||||||
check_abi(tcx, id, span, fn_sig.abi());
|
|
||||||
|
|
||||||
// Compute the function signature from point of view of inside the fn.
|
|
||||||
let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
|
|
||||||
let fn_sig = inh.normalize_associated_types_in(
|
|
||||||
body.value.span,
|
|
||||||
body_id.hir_id,
|
|
||||||
param_env,
|
|
||||||
fn_sig,
|
|
||||||
);
|
|
||||||
check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
|
|
||||||
} else {
|
|
||||||
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
|
|
||||||
let expected_type = body_ty
|
|
||||||
.and_then(|ty| match ty.kind {
|
|
||||||
hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| match tcx.hir().get(id) {
|
|
||||||
Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
|
|
||||||
Node::Expr(&hir::Expr {
|
|
||||||
kind: hir::ExprKind::ConstBlock(ref anon_const),
|
|
||||||
..
|
|
||||||
}) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
|
|
||||||
kind: TypeVariableOriginKind::TypeInference,
|
|
||||||
span,
|
|
||||||
}),
|
|
||||||
Node::Ty(&hir::Ty {
|
|
||||||
kind: hir::TyKind::Typeof(ref anon_const), ..
|
|
||||||
}) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
|
|
||||||
kind: TypeVariableOriginKind::TypeInference,
|
|
||||||
span,
|
|
||||||
}),
|
|
||||||
Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
|
|
||||||
| Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
|
|
||||||
let operand_ty = asm
|
|
||||||
.operands
|
|
||||||
.iter()
|
|
||||||
.filter_map(|(op, _op_sp)| match op {
|
|
||||||
hir::InlineAsmOperand::Const { anon_const }
|
|
||||||
if anon_const.hir_id == id =>
|
|
||||||
{
|
|
||||||
// Inline assembly constants must be integers.
|
|
||||||
Some(fcx.next_int_var())
|
|
||||||
}
|
|
||||||
hir::InlineAsmOperand::SymFn { anon_const }
|
|
||||||
if anon_const.hir_id == id =>
|
|
||||||
{
|
|
||||||
Some(fcx.next_ty_var(TypeVariableOrigin {
|
|
||||||
kind: TypeVariableOriginKind::MiscVariable,
|
|
||||||
span,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.next();
|
|
||||||
operand_ty.unwrap_or_else(fallback)
|
|
||||||
}
|
|
||||||
_ => fallback(),
|
|
||||||
},
|
|
||||||
_ => fallback(),
|
|
||||||
});
|
|
||||||
|
|
||||||
let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
|
|
||||||
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
|
|
||||||
|
|
||||||
// Gather locals in statics (because of block expressions).
|
|
||||||
GatherLocalsVisitor::new(&fcx).visit_body(body);
|
|
||||||
|
|
||||||
fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
|
|
||||||
|
|
||||||
fcx.write_ty(id, expected_type);
|
|
||||||
|
|
||||||
fcx
|
|
||||||
};
|
|
||||||
|
|
||||||
let fallback_has_occurred = fcx.type_inference_fallback();
|
|
||||||
|
|
||||||
// Even though coercion casts provide type hints, we check casts after fallback for
|
|
||||||
// backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
|
|
||||||
fcx.check_casts();
|
|
||||||
fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
|
|
||||||
|
|
||||||
// Closure and generator analysis may run after fallback
|
|
||||||
// because they don't constrain other type variables.
|
|
||||||
// Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now)
|
|
||||||
let prev_constness = fcx.param_env.constness();
|
|
||||||
fcx.param_env = fcx.param_env.without_const();
|
|
||||||
fcx.closure_analyze(body);
|
|
||||||
fcx.param_env = fcx.param_env.with_constness(prev_constness);
|
|
||||||
assert!(fcx.deferred_call_resolutions.borrow().is_empty());
|
|
||||||
// Before the generator analysis, temporary scopes shall be marked to provide more
|
|
||||||
// precise information on types to be captured.
|
|
||||||
fcx.resolve_rvalue_scopes(def_id.to_def_id());
|
|
||||||
fcx.resolve_generator_interiors(def_id.to_def_id());
|
|
||||||
|
|
||||||
for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
|
|
||||||
let ty = fcx.normalize_ty(span, ty);
|
|
||||||
fcx.require_type_is_sized(ty, span, code);
|
|
||||||
}
|
|
||||||
|
|
||||||
fcx.select_all_obligations_or_error();
|
|
||||||
|
|
||||||
if !fcx.infcx.is_tainted_by_errors() {
|
|
||||||
fcx.check_transmutes();
|
|
||||||
}
|
|
||||||
|
|
||||||
fcx.check_asms();
|
|
||||||
|
|
||||||
fcx.infcx.skip_region_resolution();
|
|
||||||
|
|
||||||
fcx.resolve_type_vars_in_body(body)
|
|
||||||
});
|
|
||||||
|
|
||||||
// Consistency check our TypeckResults instance can hold all ItemLocalIds
|
|
||||||
// it will need to hold.
|
|
||||||
assert_eq!(typeck_results.hir_owner, id.owner);
|
|
||||||
|
|
||||||
typeck_results
|
|
||||||
}
|
|
||||||
|
|
||||||
/// When `check_fn` is invoked on a generator (i.e., a body that
|
|
||||||
/// includes yield), it returns back some information about the yield
|
|
||||||
/// points.
|
|
||||||
struct GeneratorTypes<'tcx> {
|
|
||||||
/// Type of generator argument / values returned by `yield`.
|
|
||||||
resume_ty: Ty<'tcx>,
|
|
||||||
|
|
||||||
/// Type of value that is yielded.
|
|
||||||
yield_ty: Ty<'tcx>,
|
|
||||||
|
|
||||||
/// Types that are captured (see `GeneratorInterior` for more).
|
|
||||||
interior: Ty<'tcx>,
|
|
||||||
|
|
||||||
/// Indicates if the generator is movable or static (immovable).
|
|
||||||
movability: hir::Movability,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given a `DefId` for an opaque type in return position, find its parent item's return
|
/// Given a `DefId` for an opaque type in return position, find its parent item's return
|
||||||
/// expressions.
|
/// expressions.
|
||||||
fn get_owner_return_paths<'tcx>(
|
fn get_owner_return_paths<'tcx>(
|
||||||
|
@ -528,9 +129,10 @@ fn get_owner_return_paths<'tcx>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forbid defining intrinsics in Rust code,
|
/// Forbid defining intrinsics in Rust code,
|
||||||
// as they must always be defined by the compiler.
|
/// as they must always be defined by the compiler.
|
||||||
fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
|
// FIXME: Move this to a more appropriate place.
|
||||||
|
pub fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
|
||||||
if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
|
if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
|
||||||
tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
|
tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
|
||||||
}
|
}
|
||||||
|
@ -824,6 +426,17 @@ fn fn_sig_suggestion<'tcx>(
|
||||||
format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
|
format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
|
||||||
|
Some(match ty.kind() {
|
||||||
|
ty::Bool => "true",
|
||||||
|
ty::Char => "'a'",
|
||||||
|
ty::Int(_) | ty::Uint(_) => "42",
|
||||||
|
ty::Float(_) => "3.14159",
|
||||||
|
ty::Error(_) | ty::Never => return None,
|
||||||
|
_ => "value",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Return placeholder code for the given associated item.
|
/// Return placeholder code for the given associated item.
|
||||||
/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
|
/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
|
||||||
/// structured suggestion.
|
/// structured suggestion.
|
||||||
|
@ -845,7 +458,7 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
|
||||||
ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
|
ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
|
||||||
ty::AssocKind::Const => {
|
ty::AssocKind::Const => {
|
||||||
let ty = tcx.type_of(assoc.def_id);
|
let ty = tcx.type_of(assoc.def_id);
|
||||||
let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
|
let val = ty_kind_suggestion(ty).unwrap_or("value");
|
||||||
format!("const {}: {} = {};", assoc.name, ty, val)
|
format!("const {}: {} = {};", assoc.name, ty, val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -896,76 +509,7 @@ fn bad_non_zero_sized_fields<'tcx>(
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) {
|
// FIXME: Consider moving this method to a more fitting place.
|
||||||
struct_span_err!(
|
pub fn potentially_plural_count(count: usize, word: &str) -> String {
|
||||||
tcx.sess,
|
|
||||||
span,
|
|
||||||
E0533,
|
|
||||||
"expected unit struct, unit variant or constant, found {} `{}`",
|
|
||||||
res.descr(),
|
|
||||||
rustc_hir_pretty::qpath_to_string(qpath),
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Controls whether the arguments are tupled. This is used for the call
|
|
||||||
/// operator.
|
|
||||||
///
|
|
||||||
/// Tupling means that all call-side arguments are packed into a tuple and
|
|
||||||
/// passed as a single parameter. For example, if tupling is enabled, this
|
|
||||||
/// function:
|
|
||||||
/// ```
|
|
||||||
/// fn f(x: (isize, isize)) {}
|
|
||||||
/// ```
|
|
||||||
/// Can be called as:
|
|
||||||
/// ```ignore UNSOLVED (can this be done in user code?)
|
|
||||||
/// # fn f(x: (isize, isize)) {}
|
|
||||||
/// f(1, 2);
|
|
||||||
/// ```
|
|
||||||
/// Instead of:
|
|
||||||
/// ```
|
|
||||||
/// # fn f(x: (isize, isize)) {}
|
|
||||||
/// f((1, 2));
|
|
||||||
/// ```
|
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
|
||||||
enum TupleArgumentsFlag {
|
|
||||||
DontTupleArguments,
|
|
||||||
TupleArguments,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
|
|
||||||
tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fatally_break_rust(sess: &Session) {
|
|
||||||
let handler = sess.diagnostic();
|
|
||||||
handler.span_bug_no_panic(
|
|
||||||
MultiSpan::new(),
|
|
||||||
"It looks like you're trying to break rust; would you like some ICE?",
|
|
||||||
);
|
|
||||||
handler.note_without_error("the compiler expectedly panicked. this is a feature.");
|
|
||||||
handler.note_without_error(
|
|
||||||
"we would appreciate a joke overview: \
|
|
||||||
https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
|
|
||||||
);
|
|
||||||
handler.note_without_error(&format!(
|
|
||||||
"rustc {} running on {}",
|
|
||||||
option_env!("CFG_VERSION").unwrap_or("unknown_version"),
|
|
||||||
config::host_triple(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn potentially_plural_count(count: usize, word: &str) -> String {
|
|
||||||
format!("{} {}{}", count, word, pluralize!(count))
|
format!("{} {}{}", count, word, pluralize!(count))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_expected_num_generic_args<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
trait_did: Option<DefId>,
|
|
||||||
expected: usize,
|
|
||||||
) -> bool {
|
|
||||||
trait_did.map_or(true, |trait_did| {
|
|
||||||
let generics = tcx.generics_of(trait_did);
|
|
||||||
generics.count() == expected + if generics.has_self { 1 } else { 0 }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,22 +1,11 @@
|
||||||
//! Errors emitted by `hir_analysis`.
|
//! Errors emitted by `rustc_hir_analysis`.
|
||||||
|
|
||||||
use rustc_errors::IntoDiagnostic;
|
use rustc_errors::IntoDiagnostic;
|
||||||
use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler};
|
use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler};
|
||||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
use rustc_macros::{Diagnostic, LintDiagnostic};
|
||||||
use rustc_middle::ty::Ty;
|
use rustc_middle::ty::Ty;
|
||||||
use rustc_span::{symbol::Ident, Span, Symbol};
|
use rustc_span::{symbol::Ident, Span, Symbol};
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(hir_analysis::field_multiply_specified_in_initializer, code = "E0062")]
|
|
||||||
pub struct FieldMultiplySpecifiedInInitializer {
|
|
||||||
#[primary_span]
|
|
||||||
#[label]
|
|
||||||
pub span: Span,
|
|
||||||
#[label(hir_analysis::previous_use_label)]
|
|
||||||
pub prev_span: Span,
|
|
||||||
pub ident: Ident,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_analysis::unrecognized_atomic_operation, code = "E0092")]
|
#[diag(hir_analysis::unrecognized_atomic_operation, code = "E0092")]
|
||||||
pub struct UnrecognizedAtomicOperation<'a> {
|
pub struct UnrecognizedAtomicOperation<'a> {
|
||||||
|
@ -124,13 +113,6 @@ pub struct AssocTypeBindingNotAllowed {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(hir_analysis::functional_record_update_on_non_struct, code = "E0436")]
|
|
||||||
pub struct FunctionalRecordUpdateOnNonStruct {
|
|
||||||
#[primary_span]
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_analysis::typeof_reserved_keyword_used, code = "E0516")]
|
#[diag(hir_analysis::typeof_reserved_keyword_used, code = "E0516")]
|
||||||
pub struct TypeofReservedKeywordUsed<'tcx> {
|
pub struct TypeofReservedKeywordUsed<'tcx> {
|
||||||
|
@ -142,39 +124,6 @@ pub struct TypeofReservedKeywordUsed<'tcx> {
|
||||||
pub opt_sugg: Option<(Span, Applicability)>,
|
pub opt_sugg: Option<(Span, Applicability)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(hir_analysis::return_stmt_outside_of_fn_body, code = "E0572")]
|
|
||||||
pub struct ReturnStmtOutsideOfFnBody {
|
|
||||||
#[primary_span]
|
|
||||||
pub span: Span,
|
|
||||||
#[label(hir_analysis::encl_body_label)]
|
|
||||||
pub encl_body_span: Option<Span>,
|
|
||||||
#[label(hir_analysis::encl_fn_label)]
|
|
||||||
pub encl_fn_span: Option<Span>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(hir_analysis::yield_expr_outside_of_generator, code = "E0627")]
|
|
||||||
pub struct YieldExprOutsideOfGenerator {
|
|
||||||
#[primary_span]
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(hir_analysis::struct_expr_non_exhaustive, code = "E0639")]
|
|
||||||
pub struct StructExprNonExhaustive {
|
|
||||||
#[primary_span]
|
|
||||||
pub span: Span,
|
|
||||||
pub what: &'static str,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(hir_analysis::method_call_on_unknown_type, code = "E0699")]
|
|
||||||
pub struct MethodCallOnUnknownType {
|
|
||||||
#[primary_span]
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_analysis::value_of_associated_struct_already_specified, code = "E0719")]
|
#[diag(hir_analysis::value_of_associated_struct_already_specified, code = "E0719")]
|
||||||
pub struct ValueOfAssociatedStructAlreadySpecified {
|
pub struct ValueOfAssociatedStructAlreadySpecified {
|
||||||
|
@ -187,52 +136,6 @@ pub struct ValueOfAssociatedStructAlreadySpecified {
|
||||||
pub def_path: String,
|
pub def_path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(hir_analysis::address_of_temporary_taken, code = "E0745")]
|
|
||||||
pub struct AddressOfTemporaryTaken {
|
|
||||||
#[primary_span]
|
|
||||||
#[label]
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
|
||||||
pub enum AddReturnTypeSuggestion {
|
|
||||||
#[suggestion(
|
|
||||||
hir_analysis::add_return_type_add,
|
|
||||||
code = "-> {found} ",
|
|
||||||
applicability = "machine-applicable"
|
|
||||||
)]
|
|
||||||
Add {
|
|
||||||
#[primary_span]
|
|
||||||
span: Span,
|
|
||||||
found: String,
|
|
||||||
},
|
|
||||||
#[suggestion(
|
|
||||||
hir_analysis::add_return_type_missing_here,
|
|
||||||
code = "-> _ ",
|
|
||||||
applicability = "has-placeholders"
|
|
||||||
)]
|
|
||||||
MissingHere {
|
|
||||||
#[primary_span]
|
|
||||||
span: Span,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
|
||||||
pub enum ExpectedReturnTypeLabel<'tcx> {
|
|
||||||
#[label(hir_analysis::expected_default_return_type)]
|
|
||||||
Unit {
|
|
||||||
#[primary_span]
|
|
||||||
span: Span,
|
|
||||||
},
|
|
||||||
#[label(hir_analysis::expected_return_type)]
|
|
||||||
Other {
|
|
||||||
#[primary_span]
|
|
||||||
span: Span,
|
|
||||||
expected: Ty<'tcx>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_analysis::unconstrained_opaque_type)]
|
#[diag(hir_analysis::unconstrained_opaque_type)]
|
||||||
#[note]
|
#[note]
|
||||||
|
@ -346,29 +249,3 @@ pub struct ExpectedUsedSymbol {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(hir_analysis::missing_parentheses_in_range, code = "E0689")]
|
|
||||||
pub struct MissingParentheseInRange {
|
|
||||||
#[primary_span]
|
|
||||||
#[label(hir_analysis::missing_parentheses_in_range)]
|
|
||||||
pub span: Span,
|
|
||||||
pub ty_str: String,
|
|
||||||
pub method_name: String,
|
|
||||||
|
|
||||||
#[subdiagnostic]
|
|
||||||
pub add_missing_parentheses: Option<AddMissingParenthesesInRange>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
|
||||||
#[multipart_suggestion_verbose(
|
|
||||||
hir_analysis::add_missing_parentheses_in_range,
|
|
||||||
applicability = "maybe-incorrect"
|
|
||||||
)]
|
|
||||||
pub struct AddMissingParenthesesInRange {
|
|
||||||
pub func_name: String,
|
|
||||||
#[suggestion_part(code = "(")]
|
|
||||||
pub left: Span,
|
|
||||||
#[suggestion_part(code = ")")]
|
|
||||||
pub right: Span,
|
|
||||||
}
|
|
||||||
|
|
|
@ -82,20 +82,19 @@ extern crate rustc_middle;
|
||||||
|
|
||||||
// These are used by Clippy.
|
// These are used by Clippy.
|
||||||
pub mod check;
|
pub mod check;
|
||||||
pub mod expr_use_visitor;
|
|
||||||
|
|
||||||
mod astconv;
|
pub mod astconv;
|
||||||
mod bounds;
|
mod bounds;
|
||||||
mod check_unused;
|
mod check_unused;
|
||||||
mod coherence;
|
mod coherence;
|
||||||
mod collect;
|
// FIXME: This module shouldn't be public.
|
||||||
|
pub mod collect;
|
||||||
mod constrained_generic_params;
|
mod constrained_generic_params;
|
||||||
mod errors;
|
mod errors;
|
||||||
pub mod hir_wf_check;
|
pub mod hir_wf_check;
|
||||||
mod impl_wf_check;
|
mod impl_wf_check;
|
||||||
mod mem_categorization;
|
|
||||||
mod outlives;
|
mod outlives;
|
||||||
mod structured_errors;
|
pub mod structured_errors;
|
||||||
mod variance;
|
mod variance;
|
||||||
|
|
||||||
use rustc_errors::{struct_span_err, ErrorGuaranteed};
|
use rustc_errors::{struct_span_err, ErrorGuaranteed};
|
||||||
|
|
28
compiler/rustc_hir_typeck/Cargo.toml
Normal file
28
compiler/rustc_hir_typeck/Cargo.toml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
[package]
|
||||||
|
name = "rustc_hir_typeck"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||||
|
tracing = "0.1"
|
||||||
|
rustc_ast = { path = "../rustc_ast" }
|
||||||
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
|
rustc_errors = { path = "../rustc_errors" }
|
||||||
|
rustc_graphviz = { path = "../rustc_graphviz" }
|
||||||
|
rustc_index = { path = "../rustc_index" }
|
||||||
|
rustc_infer = { path = "../rustc_infer" }
|
||||||
|
rustc_hir = { path = "../rustc_hir" }
|
||||||
|
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
|
||||||
|
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
|
||||||
|
rustc_lint = { path = "../rustc_lint" }
|
||||||
|
rustc_middle = { path = "../rustc_middle" }
|
||||||
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
|
rustc_serialize = { path = "../rustc_serialize" }
|
||||||
|
rustc_session = { path = "../rustc_session" }
|
||||||
|
rustc_span = { path = "../rustc_span" }
|
||||||
|
rustc_target = { path = "../rustc_target" }
|
||||||
|
rustc_trait_selection = { path = "../rustc_trait_selection" }
|
||||||
|
rustc_type_ir = { path = "../rustc_type_ir" }
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::check::coercion::{AsCoercionSite, CoerceMany};
|
use crate::coercion::{AsCoercionSite, CoerceMany};
|
||||||
use crate::check::{Diverges, Expectation, FnCtxt, Needs};
|
use crate::{Diverges, Expectation, FnCtxt, Needs};
|
||||||
use rustc_errors::{Applicability, MultiSpan};
|
use rustc_errors::{Applicability, MultiSpan};
|
||||||
use rustc_hir::{self as hir, ExprKind};
|
use rustc_hir::{self as hir, ExprKind};
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use super::method::probe::{IsSuggestion, Mode, ProbeScope};
|
use super::method::probe::{IsSuggestion, Mode, ProbeScope};
|
||||||
use super::method::MethodCallee;
|
use super::method::MethodCallee;
|
||||||
use super::{Expectation, FnCtxt, TupleArgumentsFlag};
|
use super::{Expectation, FnCtxt, TupleArgumentsFlag};
|
||||||
use crate::type_error_struct;
|
|
||||||
|
|
||||||
|
use crate::type_error_struct;
|
||||||
use rustc_ast::util::parser::PREC_POSTFIX;
|
use rustc_ast::util::parser::PREC_POSTFIX;
|
||||||
use rustc_errors::{struct_span_err, Applicability, Diagnostic, StashKey};
|
use rustc_errors::{struct_span_err, Applicability, Diagnostic, StashKey};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
|
|
@ -30,9 +30,7 @@
|
||||||
|
|
||||||
use super::FnCtxt;
|
use super::FnCtxt;
|
||||||
|
|
||||||
use crate::hir::def_id::DefId;
|
|
||||||
use crate::type_error_struct;
|
use crate::type_error_struct;
|
||||||
use hir::def_id::LOCAL_CRATE;
|
|
||||||
use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
|
use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_middle::mir::Mutability;
|
use rustc_middle::mir::Mutability;
|
||||||
|
@ -43,6 +41,7 @@ use rustc_middle::ty::subst::SubstsRef;
|
||||||
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
|
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
|
use rustc_span::def_id::{DefId, LOCAL_CRATE};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
|
@ -527,7 +526,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
CastError::SizedUnsizedCast => {
|
CastError::SizedUnsizedCast => {
|
||||||
use crate::structured_errors::{SizedUnsizedCast, StructuredDiagnostic};
|
use rustc_hir_analysis::structured_errors::{
|
||||||
|
SizedUnsizedCast, StructuredDiagnostic,
|
||||||
|
};
|
||||||
|
|
||||||
SizedUnsizedCast {
|
SizedUnsizedCast {
|
||||||
sess: &fcx.tcx.sess,
|
sess: &fcx.tcx.sess,
|
||||||
|
|
324
compiler/rustc_hir_typeck/src/check.rs
Normal file
324
compiler/rustc_hir_typeck/src/check.rs
Normal file
|
@ -0,0 +1,324 @@
|
||||||
|
use crate::coercion::CoerceMany;
|
||||||
|
use crate::gather_locals::GatherLocalsVisitor;
|
||||||
|
use crate::{FnCtxt, Inherited};
|
||||||
|
use crate::{GeneratorTypes, UnsafetyState};
|
||||||
|
use rustc_hir as hir;
|
||||||
|
use rustc_hir::def::DefKind;
|
||||||
|
use rustc_hir::intravisit::Visitor;
|
||||||
|
use rustc_hir::lang_items::LangItem;
|
||||||
|
use rustc_hir::{ImplicitSelfKind, ItemKind, Node};
|
||||||
|
use rustc_hir_analysis::check::fn_maybe_err;
|
||||||
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
|
use rustc_infer::infer::RegionVariableOrigin;
|
||||||
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
|
use rustc_span::def_id::LocalDefId;
|
||||||
|
use rustc_target::spec::abi::Abi;
|
||||||
|
use rustc_trait_selection::traits;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
/// Helper used for fns and closures. Does the grungy work of checking a function
|
||||||
|
/// body and returns the function context used for that purpose, since in the case of a fn item
|
||||||
|
/// there is still a bit more to do.
|
||||||
|
///
|
||||||
|
/// * ...
|
||||||
|
/// * inherited: other fields inherited from the enclosing fn (if any)
|
||||||
|
#[instrument(skip(inherited, body), level = "debug")]
|
||||||
|
pub(super) fn check_fn<'a, 'tcx>(
|
||||||
|
inherited: &'a Inherited<'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
fn_sig: ty::FnSig<'tcx>,
|
||||||
|
decl: &'tcx hir::FnDecl<'tcx>,
|
||||||
|
fn_id: hir::HirId,
|
||||||
|
body: &'tcx hir::Body<'tcx>,
|
||||||
|
can_be_generator: Option<hir::Movability>,
|
||||||
|
return_type_pre_known: bool,
|
||||||
|
) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
|
||||||
|
// Create the function context. This is either derived from scratch or,
|
||||||
|
// in the case of closures, based on the outer context.
|
||||||
|
let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
|
||||||
|
fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
|
||||||
|
fcx.return_type_pre_known = return_type_pre_known;
|
||||||
|
|
||||||
|
let tcx = fcx.tcx;
|
||||||
|
let hir = tcx.hir();
|
||||||
|
|
||||||
|
let declared_ret_ty = fn_sig.output();
|
||||||
|
|
||||||
|
let ret_ty =
|
||||||
|
fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
|
||||||
|
declared_ret_ty,
|
||||||
|
body.value.hir_id,
|
||||||
|
decl.output.span(),
|
||||||
|
param_env,
|
||||||
|
));
|
||||||
|
// If we replaced declared_ret_ty with infer vars, then we must be inferring
|
||||||
|
// an opaque type, so set a flag so we can improve diagnostics.
|
||||||
|
fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
|
||||||
|
|
||||||
|
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
|
||||||
|
|
||||||
|
let span = body.value.span;
|
||||||
|
|
||||||
|
fn_maybe_err(tcx, span, fn_sig.abi);
|
||||||
|
|
||||||
|
if fn_sig.abi == Abi::RustCall {
|
||||||
|
let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
|
||||||
|
|
||||||
|
let err = || {
|
||||||
|
let item = match tcx.hir().get(fn_id) {
|
||||||
|
Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
|
||||||
|
Node::ImplItem(hir::ImplItem {
|
||||||
|
kind: hir::ImplItemKind::Fn(header, ..), ..
|
||||||
|
}) => Some(header),
|
||||||
|
Node::TraitItem(hir::TraitItem {
|
||||||
|
kind: hir::TraitItemKind::Fn(header, ..),
|
||||||
|
..
|
||||||
|
}) => Some(header),
|
||||||
|
// Closures are RustCall, but they tuple their arguments, so shouldn't be checked
|
||||||
|
Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None,
|
||||||
|
node => bug!("Item being checked wasn't a function/closure: {:?}", node),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(header) = item {
|
||||||
|
tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if fn_sig.inputs().len() != expected_args {
|
||||||
|
err()
|
||||||
|
} else {
|
||||||
|
// FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
|
||||||
|
// This will probably require wide-scale changes to support a TupleKind obligation
|
||||||
|
// We can't resolve this without knowing the type of the param
|
||||||
|
if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
|
||||||
|
err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if body.generator_kind.is_some() && can_be_generator.is_some() {
|
||||||
|
let yield_ty = fcx
|
||||||
|
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
|
||||||
|
fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
|
||||||
|
|
||||||
|
// Resume type defaults to `()` if the generator has no argument.
|
||||||
|
let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
|
||||||
|
|
||||||
|
fcx.resume_yield_tys = Some((resume_ty, yield_ty));
|
||||||
|
}
|
||||||
|
|
||||||
|
GatherLocalsVisitor::new(&fcx).visit_body(body);
|
||||||
|
|
||||||
|
// C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
|
||||||
|
// (as it's created inside the body itself, not passed in from outside).
|
||||||
|
let maybe_va_list = if fn_sig.c_variadic {
|
||||||
|
let span = body.params.last().unwrap().span;
|
||||||
|
let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
|
||||||
|
let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
|
||||||
|
|
||||||
|
Some(tcx.bound_type_of(va_list_did).subst(tcx, &[region.into()]))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add formal parameters.
|
||||||
|
let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
|
||||||
|
let inputs_fn = fn_sig.inputs().iter().copied();
|
||||||
|
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
|
||||||
|
// Check the pattern.
|
||||||
|
let ty_span = try { inputs_hir?.get(idx)?.span };
|
||||||
|
fcx.check_pat_top(¶m.pat, param_ty, ty_span, false);
|
||||||
|
|
||||||
|
// Check that argument is Sized.
|
||||||
|
// The check for a non-trivial pattern is a hack to avoid duplicate warnings
|
||||||
|
// for simple cases like `fn foo(x: Trait)`,
|
||||||
|
// where we would error once on the parameter as a whole, and once on the binding `x`.
|
||||||
|
if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params {
|
||||||
|
fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
|
||||||
|
}
|
||||||
|
|
||||||
|
fcx.write_ty(param.hir_id, param_ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
|
||||||
|
|
||||||
|
fcx.in_tail_expr = true;
|
||||||
|
if let ty::Dynamic(..) = declared_ret_ty.kind() {
|
||||||
|
// FIXME: We need to verify that the return type is `Sized` after the return expression has
|
||||||
|
// been evaluated so that we have types available for all the nodes being returned, but that
|
||||||
|
// requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
|
||||||
|
// causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
|
||||||
|
// while keeping the current ordering we will ignore the tail expression's type because we
|
||||||
|
// don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
|
||||||
|
// because we will trigger "unreachable expression" lints unconditionally.
|
||||||
|
// Because of all of this, we perform a crude check to know whether the simplest `!Sized`
|
||||||
|
// case that a newcomer might make, returning a bare trait, and in that case we populate
|
||||||
|
// the tail expression's type so that the suggestion will be correct, but ignore all other
|
||||||
|
// possible cases.
|
||||||
|
fcx.check_expr(&body.value);
|
||||||
|
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
|
||||||
|
} else {
|
||||||
|
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
|
||||||
|
fcx.check_return_expr(&body.value, false);
|
||||||
|
}
|
||||||
|
fcx.in_tail_expr = false;
|
||||||
|
|
||||||
|
// We insert the deferred_generator_interiors entry after visiting the body.
|
||||||
|
// This ensures that all nested generators appear before the entry of this generator.
|
||||||
|
// resolve_generator_interiors relies on this property.
|
||||||
|
let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
|
||||||
|
let interior = fcx
|
||||||
|
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
|
||||||
|
fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
|
||||||
|
|
||||||
|
let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
|
||||||
|
Some(GeneratorTypes {
|
||||||
|
resume_ty,
|
||||||
|
yield_ty,
|
||||||
|
interior,
|
||||||
|
movability: can_be_generator.unwrap(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// really expected to fail, since the coercions would have failed
|
||||||
|
// earlier when trying to find a LUB.
|
||||||
|
let coercion = fcx.ret_coercion.take().unwrap().into_inner();
|
||||||
|
let mut actual_return_ty = coercion.complete(&fcx);
|
||||||
|
debug!("actual_return_ty = {:?}", actual_return_ty);
|
||||||
|
if let ty::Dynamic(..) = declared_ret_ty.kind() {
|
||||||
|
// We have special-cased the case where the function is declared
|
||||||
|
// `-> dyn Foo` and we don't actually relate it to the
|
||||||
|
// `fcx.ret_coercion`, so just substitute a type variable.
|
||||||
|
actual_return_ty =
|
||||||
|
fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
|
||||||
|
debug!("actual_return_ty replaced with {:?}", actual_return_ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// HACK(oli-obk, compiler-errors): We should be comparing this against
|
||||||
|
// `declared_ret_ty`, but then anything uninferred would be inferred to
|
||||||
|
// the opaque type itself. That again would cause writeback to assume
|
||||||
|
// we have a recursive call site and do the sadly stabilized fallback to `()`.
|
||||||
|
fcx.demand_suptype(span, ret_ty, actual_return_ty);
|
||||||
|
|
||||||
|
// Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
|
||||||
|
if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
|
||||||
|
&& panic_impl_did == hir.local_def_id(fn_id).to_def_id()
|
||||||
|
{
|
||||||
|
check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
|
||||||
|
if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
|
||||||
|
&& alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
|
||||||
|
{
|
||||||
|
check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
(fcx, gen_ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_panic_info_fn(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
fn_id: LocalDefId,
|
||||||
|
fn_sig: ty::FnSig<'_>,
|
||||||
|
decl: &hir::FnDecl<'_>,
|
||||||
|
declared_ret_ty: Ty<'_>,
|
||||||
|
) {
|
||||||
|
let Some(panic_info_did) = tcx.lang_items().panic_info() else {
|
||||||
|
tcx.sess.err("language item required, but not found: `panic_info`");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if *declared_ret_ty.kind() != ty::Never {
|
||||||
|
tcx.sess.span_err(decl.output.span(), "return type should be `!`");
|
||||||
|
}
|
||||||
|
|
||||||
|
let inputs = fn_sig.inputs();
|
||||||
|
if inputs.len() != 1 {
|
||||||
|
tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let arg_is_panic_info = match *inputs[0].kind() {
|
||||||
|
ty::Ref(region, ty, mutbl) => match *ty.kind() {
|
||||||
|
ty::Adt(ref adt, _) => {
|
||||||
|
adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if !arg_is_panic_info {
|
||||||
|
tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
|
||||||
|
}
|
||||||
|
|
||||||
|
let DefKind::Fn = tcx.def_kind(fn_id) else {
|
||||||
|
let span = tcx.def_span(fn_id);
|
||||||
|
tcx.sess.span_err(span, "should be a function");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let generic_counts = tcx.generics_of(fn_id).own_counts();
|
||||||
|
if generic_counts.types != 0 {
|
||||||
|
let span = tcx.def_span(fn_id);
|
||||||
|
tcx.sess.span_err(span, "should have no type parameters");
|
||||||
|
}
|
||||||
|
if generic_counts.consts != 0 {
|
||||||
|
let span = tcx.def_span(fn_id);
|
||||||
|
tcx.sess.span_err(span, "should have no const parameters");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_alloc_error_fn(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
fn_id: LocalDefId,
|
||||||
|
fn_sig: ty::FnSig<'_>,
|
||||||
|
decl: &hir::FnDecl<'_>,
|
||||||
|
declared_ret_ty: Ty<'_>,
|
||||||
|
) {
|
||||||
|
let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
|
||||||
|
tcx.sess.err("language item required, but not found: `alloc_layout`");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if *declared_ret_ty.kind() != ty::Never {
|
||||||
|
tcx.sess.span_err(decl.output.span(), "return type should be `!`");
|
||||||
|
}
|
||||||
|
|
||||||
|
let inputs = fn_sig.inputs();
|
||||||
|
if inputs.len() != 1 {
|
||||||
|
tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let arg_is_alloc_layout = match inputs[0].kind() {
|
||||||
|
ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if !arg_is_alloc_layout {
|
||||||
|
tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
|
||||||
|
}
|
||||||
|
|
||||||
|
let DefKind::Fn = tcx.def_kind(fn_id) else {
|
||||||
|
let span = tcx.def_span(fn_id);
|
||||||
|
tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let generic_counts = tcx.generics_of(fn_id).own_counts();
|
||||||
|
if generic_counts.types != 0 {
|
||||||
|
let span = tcx.def_span(fn_id);
|
||||||
|
tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
|
||||||
|
}
|
||||||
|
if generic_counts.consts != 0 {
|
||||||
|
let span = tcx.def_span(fn_id);
|
||||||
|
tcx.sess
|
||||||
|
.span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
|
use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
|
||||||
|
|
||||||
use crate::astconv::AstConv;
|
|
||||||
use hir::def::DefKind;
|
use hir::def::DefKind;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
|
use rustc_hir_analysis::astconv::AstConv;
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use rustc_infer::infer::LateBoundRegionConversionTime;
|
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||||
use rustc_infer::infer::{InferOk, InferResult};
|
use rustc_infer::infer::{InferOk, InferResult};
|
||||||
|
|
|
@ -35,8 +35,7 @@
|
||||||
//! // and are then unable to coerce `&7i32` to `&mut i32`.
|
//! // and are then unable to coerce `&7i32` to `&mut i32`.
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use crate::astconv::AstConv;
|
use crate::FnCtxt;
|
||||||
use crate::check::FnCtxt;
|
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
|
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
|
||||||
};
|
};
|
||||||
|
@ -44,6 +43,7 @@ use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::Expr;
|
use rustc_hir::Expr;
|
||||||
|
use rustc_hir_analysis::astconv::AstConv;
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use rustc_infer::infer::{Coercion, InferOk, InferResult};
|
use rustc_infer::infer::{Coercion, InferOk, InferResult};
|
||||||
use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt};
|
use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt};
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
use crate::check::FnCtxt;
|
use crate::FnCtxt;
|
||||||
use rustc_infer::infer::InferOk;
|
|
||||||
use rustc_middle::middle::stability::EvalResult;
|
|
||||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
|
||||||
use rustc_trait_selection::traits::ObligationCause;
|
|
||||||
|
|
||||||
use rustc_ast::util::parser::PREC_POSTFIX;
|
use rustc_ast::util::parser::PREC_POSTFIX;
|
||||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::{is_range_literal, Node};
|
use rustc_hir::{is_range_literal, Node};
|
||||||
|
use rustc_infer::infer::InferOk;
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
|
use rustc_middle::middle::stability::EvalResult;
|
||||||
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
||||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut};
|
use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut};
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
use rustc_span::{BytePos, Span};
|
use rustc_span::{BytePos, Span};
|
||||||
|
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||||
|
use rustc_trait_selection::traits::ObligationCause;
|
||||||
|
|
||||||
use super::method::probe;
|
use super::method::probe;
|
||||||
|
|
||||||
|
|
127
compiler/rustc_hir_typeck/src/errors.rs
Normal file
127
compiler/rustc_hir_typeck/src/errors.rs
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
//! Errors emitted by `rustc_hir_analysis`.
|
||||||
|
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||||
|
use rustc_middle::ty::Ty;
|
||||||
|
use rustc_span::{symbol::Ident, Span};
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(hir_analysis::field_multiply_specified_in_initializer, code = "E0062")]
|
||||||
|
pub struct FieldMultiplySpecifiedInInitializer {
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
#[label(hir_analysis::previous_use_label)]
|
||||||
|
pub prev_span: Span,
|
||||||
|
pub ident: Ident,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(hir_analysis::return_stmt_outside_of_fn_body, code = "E0572")]
|
||||||
|
pub struct ReturnStmtOutsideOfFnBody {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
#[label(hir_analysis::encl_body_label)]
|
||||||
|
pub encl_body_span: Option<Span>,
|
||||||
|
#[label(hir_analysis::encl_fn_label)]
|
||||||
|
pub encl_fn_span: Option<Span>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(hir_analysis::yield_expr_outside_of_generator, code = "E0627")]
|
||||||
|
pub struct YieldExprOutsideOfGenerator {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(hir_analysis::struct_expr_non_exhaustive, code = "E0639")]
|
||||||
|
pub struct StructExprNonExhaustive {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
pub what: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(hir_analysis::method_call_on_unknown_type, code = "E0699")]
|
||||||
|
pub struct MethodCallOnUnknownType {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(hir_analysis::functional_record_update_on_non_struct, code = "E0436")]
|
||||||
|
pub struct FunctionalRecordUpdateOnNonStruct {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(hir_analysis::address_of_temporary_taken, code = "E0745")]
|
||||||
|
pub struct AddressOfTemporaryTaken {
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
pub enum AddReturnTypeSuggestion {
|
||||||
|
#[suggestion(
|
||||||
|
hir_analysis::add_return_type_add,
|
||||||
|
code = "-> {found} ",
|
||||||
|
applicability = "machine-applicable"
|
||||||
|
)]
|
||||||
|
Add {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
found: String,
|
||||||
|
},
|
||||||
|
#[suggestion(
|
||||||
|
hir_analysis::add_return_type_missing_here,
|
||||||
|
code = "-> _ ",
|
||||||
|
applicability = "has-placeholders"
|
||||||
|
)]
|
||||||
|
MissingHere {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
pub enum ExpectedReturnTypeLabel<'tcx> {
|
||||||
|
#[label(hir_analysis::expected_default_return_type)]
|
||||||
|
Unit {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
},
|
||||||
|
#[label(hir_analysis::expected_return_type)]
|
||||||
|
Other {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
expected: Ty<'tcx>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(hir_analysis::missing_parentheses_in_range, code = "E0689")]
|
||||||
|
pub struct MissingParentheseInRange {
|
||||||
|
#[primary_span]
|
||||||
|
#[label(hir_analysis::missing_parentheses_in_range)]
|
||||||
|
pub span: Span,
|
||||||
|
pub ty_str: String,
|
||||||
|
pub method_name: String,
|
||||||
|
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub add_missing_parentheses: Option<AddMissingParenthesesInRange>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[multipart_suggestion_verbose(
|
||||||
|
hir_analysis::add_missing_parentheses_in_range,
|
||||||
|
applicability = "maybe-incorrect"
|
||||||
|
)]
|
||||||
|
pub struct AddMissingParenthesesInRange {
|
||||||
|
pub func_name: String,
|
||||||
|
#[suggestion_part(code = "(")]
|
||||||
|
pub left: Span,
|
||||||
|
#[suggestion_part(code = ")")]
|
||||||
|
pub right: Span,
|
||||||
|
}
|
|
@ -2,23 +2,22 @@
|
||||||
//!
|
//!
|
||||||
//! See `mod.rs` for more context on type checking in general.
|
//! See `mod.rs` for more context on type checking in general.
|
||||||
|
|
||||||
use crate::astconv::AstConv as _;
|
use crate::cast;
|
||||||
use crate::check::cast;
|
use crate::coercion::CoerceMany;
|
||||||
use crate::check::coercion::CoerceMany;
|
use crate::coercion::DynamicCoerceMany;
|
||||||
use crate::check::fatally_break_rust;
|
use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
|
||||||
use crate::check::method::SelfSource;
|
|
||||||
use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
|
|
||||||
use crate::check::{
|
|
||||||
report_unexpected_variant_res, BreakableCtxt, Diverges, DynamicCoerceMany, FnCtxt, Needs,
|
|
||||||
TupleArgumentsFlag::DontTupleArguments,
|
|
||||||
};
|
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
|
FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
|
||||||
YieldExprOutsideOfGenerator,
|
YieldExprOutsideOfGenerator,
|
||||||
};
|
};
|
||||||
|
use crate::fatally_break_rust;
|
||||||
|
use crate::method::SelfSource;
|
||||||
use crate::type_error_struct;
|
use crate::type_error_struct;
|
||||||
|
use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
|
||||||
use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
|
use crate::{
|
||||||
|
report_unexpected_variant_res, BreakableCtxt, Diverges, FnCtxt, Needs,
|
||||||
|
TupleArgumentsFlag::DontTupleArguments,
|
||||||
|
};
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
|
@ -32,6 +31,8 @@ use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::Visitor;
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::{Closure, ExprKind, HirId, QPath};
|
use rustc_hir::{Closure, ExprKind, HirId, QPath};
|
||||||
|
use rustc_hir_analysis::astconv::AstConv as _;
|
||||||
|
use rustc_hir_analysis::check::ty_kind_suggestion;
|
||||||
use rustc_infer::infer;
|
use rustc_infer::infer;
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use rustc_infer::infer::InferOk;
|
use rustc_infer::infer::InferOk;
|
||||||
|
@ -1362,7 +1363,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
// Create a new function context.
|
// Create a new function context.
|
||||||
let fcx = FnCtxt::new(self, self.param_env.with_const(), body.value.hir_id);
|
let fcx = FnCtxt::new(self, self.param_env.with_const(), body.value.hir_id);
|
||||||
crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body);
|
crate::GatherLocalsVisitor::new(&fcx).visit_body(body);
|
||||||
|
|
||||||
let ty = fcx.check_expr_with_expectation(&body.value, expected);
|
let ty = fcx.check_expr_with_expectation(&body.value, expected);
|
||||||
fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized);
|
fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized);
|
||||||
|
@ -2885,14 +2886,3 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
|
|
||||||
Some(match ty.kind() {
|
|
||||||
ty::Bool => "true",
|
|
||||||
ty::Char => "'a'",
|
|
||||||
ty::Int(_) | ty::Uint(_) => "42",
|
|
||||||
ty::Float(_) => "3.14159",
|
|
||||||
ty::Error(_) | ty::Never => return None,
|
|
||||||
_ => "value",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -89,15 +89,6 @@ enum ConsumeMode {
|
||||||
Move,
|
Move,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
|
||||||
pub enum MutateMode {
|
|
||||||
Init,
|
|
||||||
/// Example: `x = y`
|
|
||||||
JustWrite,
|
|
||||||
/// Example: `x += y`
|
|
||||||
WriteAndRead,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The ExprUseVisitor type
|
/// The ExprUseVisitor type
|
||||||
///
|
///
|
||||||
/// This is the code that actually walks the tree.
|
/// This is the code that actually walks the tree.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::check::FnCtxt;
|
use crate::FnCtxt;
|
||||||
use rustc_data_structures::{
|
use rustc_data_structures::{
|
||||||
fx::{FxHashMap, FxHashSet},
|
fx::{FxHashMap, FxHashSet},
|
||||||
graph::WithSuccessors,
|
graph::WithSuccessors,
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
use crate::astconv::{
|
use crate::callee::{self, DeferredCallResolution};
|
||||||
AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
|
use crate::method::{self, MethodCallee, SelfSource};
|
||||||
GenericArgCountResult, IsMethodCall, PathSeg,
|
use crate::rvalue_scopes;
|
||||||
};
|
use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
|
||||||
use crate::check::callee::{self, DeferredCallResolution};
|
|
||||||
use crate::check::method::{self, MethodCallee, SelfSource};
|
|
||||||
use crate::check::rvalue_scopes;
|
|
||||||
use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
|
|
||||||
|
|
||||||
use rustc_data_structures::captures::Captures;
|
use rustc_data_structures::captures::Captures;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
|
use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
|
||||||
|
@ -15,6 +10,10 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::{ExprKind, GenericArg, Node, QPath};
|
use rustc_hir::{ExprKind, GenericArg, Node, QPath};
|
||||||
|
use rustc_hir_analysis::astconv::{
|
||||||
|
AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
|
||||||
|
GenericArgCountResult, IsMethodCall, PathSeg,
|
||||||
|
};
|
||||||
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
|
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
|
||||||
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
|
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
|
||||||
use rustc_infer::infer::{InferOk, InferResult};
|
use rustc_infer::infer::{InferOk, InferResult};
|
||||||
|
@ -603,9 +602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let mut generators = self.deferred_generator_interiors.borrow_mut();
|
let mut generators = self.deferred_generator_interiors.borrow_mut();
|
||||||
for (body_id, interior, kind) in generators.drain(..) {
|
for (body_id, interior, kind) in generators.drain(..) {
|
||||||
self.select_obligations_where_possible(false, |_| {});
|
self.select_obligations_where_possible(false, |_| {});
|
||||||
crate::check::generator_interior::resolve_interior(
|
crate::generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
|
||||||
self, def_id, body_id, interior, kind,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,13 @@
|
||||||
use crate::astconv::AstConv;
|
use crate::coercion::CoerceMany;
|
||||||
use crate::check::coercion::CoerceMany;
|
use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx};
|
||||||
use crate::check::fn_ctxt::arg_matrix::{
|
use crate::gather_locals::Declaration;
|
||||||
ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx,
|
use crate::method::MethodCallee;
|
||||||
|
use crate::Expectation::*;
|
||||||
|
use crate::TupleArgumentsFlag::*;
|
||||||
|
use crate::{
|
||||||
|
struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs,
|
||||||
|
TupleArgumentsFlag,
|
||||||
};
|
};
|
||||||
use crate::check::gather_locals::Declaration;
|
|
||||||
use crate::check::intrinsicck::InlineAsmCtxt;
|
|
||||||
use crate::check::method::MethodCallee;
|
|
||||||
use crate::check::Expectation::*;
|
|
||||||
use crate::check::TupleArgumentsFlag::*;
|
|
||||||
use crate::check::{
|
|
||||||
potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt,
|
|
||||||
LocalTy, Needs, TupleArgumentsFlag,
|
|
||||||
};
|
|
||||||
use crate::structured_errors::StructuredDiagnostic;
|
|
||||||
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticId, MultiSpan};
|
use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticId, MultiSpan};
|
||||||
|
@ -21,6 +15,10 @@ use rustc_hir as hir;
|
||||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::{ExprKind, Node, QPath};
|
use rustc_hir::{ExprKind, Node, QPath};
|
||||||
|
use rustc_hir_analysis::astconv::AstConv;
|
||||||
|
use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt;
|
||||||
|
use rustc_hir_analysis::check::potentially_plural_count;
|
||||||
|
use rustc_hir_analysis::structured_errors::StructuredDiagnostic;
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
|
use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
|
@ -391,7 +389,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
cast_ty: &str,
|
cast_ty: &str,
|
||||||
) {
|
) {
|
||||||
use crate::structured_errors::MissingCastForVariadicArg;
|
use rustc_hir_analysis::structured_errors::MissingCastForVariadicArg;
|
||||||
|
|
||||||
MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit();
|
MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,11 @@ mod suggestions;
|
||||||
pub use _impl::*;
|
pub use _impl::*;
|
||||||
pub use suggestions::*;
|
pub use suggestions::*;
|
||||||
|
|
||||||
use crate::astconv::AstConv;
|
use crate::coercion::DynamicCoerceMany;
|
||||||
use crate::check::coercion::DynamicCoerceMany;
|
use crate::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
|
||||||
use crate::check::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
|
|
||||||
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
use rustc_hir_analysis::astconv::AstConv;
|
||||||
use rustc_infer::infer;
|
use rustc_infer::infer;
|
||||||
use rustc_infer::infer::error_reporting::TypeErrCtxt;
|
use rustc_infer::infer::error_reporting::TypeErrCtxt;
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use super::FnCtxt;
|
use super::FnCtxt;
|
||||||
use crate::astconv::AstConv;
|
|
||||||
use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
|
|
||||||
|
|
||||||
|
use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
|
||||||
use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
|
use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
|
||||||
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
|
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
@ -10,6 +9,7 @@ use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
|
Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
|
||||||
};
|
};
|
||||||
|
use rustc_hir_analysis::astconv::AstConv;
|
||||||
use rustc_infer::infer::{self, TyCtxtInferExt};
|
use rustc_infer::infer::{self, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::{self, StatementAsExpression};
|
use rustc_infer::traits::{self, StatementAsExpression};
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::check::{FnCtxt, LocalTy, UserType};
|
use crate::{FnCtxt, LocalTy};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::PatKind;
|
use rustc_hir::PatKind;
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use rustc_middle::ty::Ty;
|
use rustc_middle::ty::Ty;
|
||||||
|
use rustc_middle::ty::UserType;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
use self::cfg_build::build_control_flow_graph;
|
use self::cfg_build::build_control_flow_graph;
|
||||||
use self::record_consumed_borrow::find_consumed_and_borrowed;
|
use self::record_consumed_borrow::find_consumed_and_borrowed;
|
||||||
use crate::check::FnCtxt;
|
use crate::FnCtxt;
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use hir::{Body, HirId, HirIdMap, Node};
|
use hir::{Body, HirId, HirIdMap, Node};
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use super::TrackedValue;
|
use super::TrackedValue;
|
||||||
use crate::{
|
use crate::{
|
||||||
check::FnCtxt,
|
|
||||||
expr_use_visitor::{self, ExprUseVisitor},
|
expr_use_visitor::{self, ExprUseVisitor},
|
||||||
|
FnCtxt,
|
||||||
};
|
};
|
||||||
use hir::{def_id::DefId, Body, HirId, HirIdMap};
|
use hir::{def_id::DefId, Body, HirId, HirIdMap};
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
|
108
compiler/rustc_hir_typeck/src/intrinsicck.rs
Normal file
108
compiler/rustc_hir_typeck/src/intrinsicck.rs
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
use hir::HirId;
|
||||||
|
use rustc_errors::struct_span_err;
|
||||||
|
use rustc_hir as hir;
|
||||||
|
use rustc_index::vec::Idx;
|
||||||
|
use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
|
||||||
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
|
use rustc_target::abi::{Pointer, VariantIdx};
|
||||||
|
|
||||||
|
use super::FnCtxt;
|
||||||
|
|
||||||
|
/// If the type is `Option<T>`, it will return `T`, otherwise
|
||||||
|
/// the type itself. Works on most `Option`-like types.
|
||||||
|
fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
|
let ty::Adt(def, substs) = *ty.kind() else { return ty };
|
||||||
|
|
||||||
|
if def.variants().len() == 2 && !def.repr().c() && def.repr().int.is_none() {
|
||||||
|
let data_idx;
|
||||||
|
|
||||||
|
let one = VariantIdx::new(1);
|
||||||
|
let zero = VariantIdx::new(0);
|
||||||
|
|
||||||
|
if def.variant(zero).fields.is_empty() {
|
||||||
|
data_idx = one;
|
||||||
|
} else if def.variant(one).fields.is_empty() {
|
||||||
|
data_idx = zero;
|
||||||
|
} else {
|
||||||
|
return ty;
|
||||||
|
}
|
||||||
|
|
||||||
|
if def.variant(data_idx).fields.len() == 1 {
|
||||||
|
return def.variant(data_idx).fields[0].ty(tcx, substs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ty
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
|
||||||
|
let tcx = self.tcx;
|
||||||
|
let span = tcx.hir().span(hir_id);
|
||||||
|
let normalize = |ty| {
|
||||||
|
let ty = self.resolve_vars_if_possible(ty);
|
||||||
|
self.tcx.normalize_erasing_regions(self.param_env, ty)
|
||||||
|
};
|
||||||
|
let from = normalize(from);
|
||||||
|
let to = normalize(to);
|
||||||
|
trace!(?from, ?to);
|
||||||
|
|
||||||
|
// Transmutes that are only changing lifetimes are always ok.
|
||||||
|
if from == to {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let skel = |ty| SizeSkeleton::compute(ty, tcx, self.param_env);
|
||||||
|
let sk_from = skel(from);
|
||||||
|
let sk_to = skel(to);
|
||||||
|
trace!(?sk_from, ?sk_to);
|
||||||
|
|
||||||
|
// Check for same size using the skeletons.
|
||||||
|
if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
|
||||||
|
if sk_from.same_size(sk_to) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special-case transmuting from `typeof(function)` and
|
||||||
|
// `Option<typeof(function)>` to present a clearer error.
|
||||||
|
let from = unpack_option_like(tcx, from);
|
||||||
|
if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&tcx) {
|
||||||
|
struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
|
||||||
|
.note(&format!("source type: {from}"))
|
||||||
|
.note(&format!("target type: {to}"))
|
||||||
|
.help("cast with `as` to a pointer instead")
|
||||||
|
.emit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to display a sensible error with as much information as possible.
|
||||||
|
let skeleton_string = |ty: Ty<'tcx>, sk| match sk {
|
||||||
|
Ok(SizeSkeleton::Known(size)) => format!("{} bits", size.bits()),
|
||||||
|
Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
|
||||||
|
Err(LayoutError::Unknown(bad)) => {
|
||||||
|
if bad == ty {
|
||||||
|
"this type does not have a fixed size".to_owned()
|
||||||
|
} else {
|
||||||
|
format!("size can vary because of {bad}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => err.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut err = struct_span_err!(
|
||||||
|
tcx.sess,
|
||||||
|
span,
|
||||||
|
E0512,
|
||||||
|
"cannot transmute between types of different sizes, \
|
||||||
|
or dependently-sized types"
|
||||||
|
);
|
||||||
|
if from == to {
|
||||||
|
err.note(&format!("`{from}` does not have a fixed size"));
|
||||||
|
} else {
|
||||||
|
err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
|
||||||
|
.note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
|
||||||
|
}
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
|
}
|
506
compiler/rustc_hir_typeck/src/lib.rs
Normal file
506
compiler/rustc_hir_typeck/src/lib.rs
Normal file
|
@ -0,0 +1,506 @@
|
||||||
|
#![feature(if_let_guard)]
|
||||||
|
#![feature(let_chains)]
|
||||||
|
#![feature(try_blocks)]
|
||||||
|
#![feature(never_type)]
|
||||||
|
#![feature(min_specialization)]
|
||||||
|
#![feature(control_flow_enum)]
|
||||||
|
#![feature(drain_filter)]
|
||||||
|
#![allow(rustc::potential_query_instability)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate tracing;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate rustc_middle;
|
||||||
|
|
||||||
|
mod _match;
|
||||||
|
mod autoderef;
|
||||||
|
mod callee;
|
||||||
|
// Used by clippy;
|
||||||
|
pub mod cast;
|
||||||
|
mod check;
|
||||||
|
mod closure;
|
||||||
|
mod coercion;
|
||||||
|
mod demand;
|
||||||
|
mod diverges;
|
||||||
|
mod errors;
|
||||||
|
mod expectation;
|
||||||
|
mod expr;
|
||||||
|
// Used by clippy;
|
||||||
|
pub mod expr_use_visitor;
|
||||||
|
mod fallback;
|
||||||
|
mod fn_ctxt;
|
||||||
|
mod gather_locals;
|
||||||
|
mod generator_interior;
|
||||||
|
mod inherited;
|
||||||
|
mod intrinsicck;
|
||||||
|
mod mem_categorization;
|
||||||
|
mod method;
|
||||||
|
mod op;
|
||||||
|
mod pat;
|
||||||
|
mod place_op;
|
||||||
|
mod rvalue_scopes;
|
||||||
|
mod upvar;
|
||||||
|
mod writeback;
|
||||||
|
|
||||||
|
pub use diverges::Diverges;
|
||||||
|
pub use expectation::Expectation;
|
||||||
|
pub use fn_ctxt::*;
|
||||||
|
pub use inherited::{Inherited, InheritedBuilder};
|
||||||
|
|
||||||
|
use crate::check::check_fn;
|
||||||
|
use crate::coercion::DynamicCoerceMany;
|
||||||
|
use crate::gather_locals::GatherLocalsVisitor;
|
||||||
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
use rustc_errors::{struct_span_err, MultiSpan};
|
||||||
|
use rustc_hir as hir;
|
||||||
|
use rustc_hir::def::Res;
|
||||||
|
use rustc_hir::intravisit::Visitor;
|
||||||
|
use rustc_hir::{HirIdMap, Node};
|
||||||
|
use rustc_hir_analysis::astconv::AstConv;
|
||||||
|
use rustc_hir_analysis::check::check_abi;
|
||||||
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
|
use rustc_middle::traits;
|
||||||
|
use rustc_middle::ty::query::Providers;
|
||||||
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
|
use rustc_session::config;
|
||||||
|
use rustc_session::Session;
|
||||||
|
use rustc_span::def_id::{DefId, LocalDefId};
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! type_error_struct {
|
||||||
|
($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
|
||||||
|
let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
|
||||||
|
|
||||||
|
if $typ.references_error() {
|
||||||
|
err.downgrade_to_delayed_bug();
|
||||||
|
}
|
||||||
|
|
||||||
|
err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The type of a local binding, including the revealed type for anon types.
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct LocalTy<'tcx> {
|
||||||
|
decl_ty: Ty<'tcx>,
|
||||||
|
revealed_ty: Ty<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct UnsafetyState {
|
||||||
|
pub def: hir::HirId,
|
||||||
|
pub unsafety: hir::Unsafety,
|
||||||
|
from_fn: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnsafetyState {
|
||||||
|
pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
|
||||||
|
UnsafetyState { def, unsafety, from_fn: true }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
|
||||||
|
use hir::BlockCheckMode;
|
||||||
|
match self.unsafety {
|
||||||
|
// If this unsafe, then if the outer function was already marked as
|
||||||
|
// unsafe we shouldn't attribute the unsafe'ness to the block. This
|
||||||
|
// way the block can be warned about instead of ignoring this
|
||||||
|
// extraneous block (functions are never warned about).
|
||||||
|
hir::Unsafety::Unsafe if self.from_fn => self,
|
||||||
|
|
||||||
|
unsafety => {
|
||||||
|
let (unsafety, def) = match blk.rules {
|
||||||
|
BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
|
||||||
|
BlockCheckMode::DefaultBlock => (unsafety, self.def),
|
||||||
|
};
|
||||||
|
UnsafetyState { def, unsafety, from_fn: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If this `DefId` is a "primary tables entry", returns
|
||||||
|
/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
|
||||||
|
///
|
||||||
|
/// If this function returns `Some`, then `typeck_results(def_id)` will
|
||||||
|
/// succeed; if it returns `None`, then `typeck_results(def_id)` may or
|
||||||
|
/// may not succeed. In some cases where this function returns `None`
|
||||||
|
/// (notably closures), `typeck_results(def_id)` would wind up
|
||||||
|
/// redirecting to the owning function.
|
||||||
|
fn primary_body_of(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
id: hir::HirId,
|
||||||
|
) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
|
||||||
|
match tcx.hir().get(id) {
|
||||||
|
Node::Item(item) => match item.kind {
|
||||||
|
hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
|
||||||
|
Some((body, Some(ty), None))
|
||||||
|
}
|
||||||
|
hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
Node::TraitItem(item) => match item.kind {
|
||||||
|
hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
|
||||||
|
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
|
||||||
|
Some((body, None, Some(sig)))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
Node::ImplItem(item) => match item.kind {
|
||||||
|
hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
|
||||||
|
hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
Node::AnonConst(constant) => Some((constant.body, None, None)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||||
|
// Closures' typeck results come from their outermost function,
|
||||||
|
// as they are part of the same "inference environment".
|
||||||
|
let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
|
||||||
|
if typeck_root_def_id != def_id {
|
||||||
|
return tcx.has_typeck_results(typeck_root_def_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(def_id) = def_id.as_local() {
|
||||||
|
let id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||||
|
primary_body_of(tcx, id).is_some()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
|
||||||
|
&*tcx.typeck(def_id).used_trait_imports
|
||||||
|
}
|
||||||
|
|
||||||
|
fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
|
||||||
|
tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn typeck_const_arg<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
(did, param_did): (LocalDefId, DefId),
|
||||||
|
) -> &ty::TypeckResults<'tcx> {
|
||||||
|
let fallback = move || tcx.type_of(param_did);
|
||||||
|
typeck_with_fallback(tcx, did, fallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
|
||||||
|
if let Some(param_did) = tcx.opt_const_param_of(def_id) {
|
||||||
|
tcx.typeck_const_arg((def_id, param_did))
|
||||||
|
} else {
|
||||||
|
let fallback = move || tcx.type_of(def_id.to_def_id());
|
||||||
|
typeck_with_fallback(tcx, def_id, fallback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used only to get `TypeckResults` for type inference during error recovery.
|
||||||
|
/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
|
||||||
|
fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
|
||||||
|
let fallback = move || {
|
||||||
|
let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
|
||||||
|
tcx.ty_error_with_message(span, "diagnostic only typeck table used")
|
||||||
|
};
|
||||||
|
typeck_with_fallback(tcx, def_id, fallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn typeck_with_fallback<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
def_id: LocalDefId,
|
||||||
|
fallback: impl Fn() -> Ty<'tcx> + 'tcx,
|
||||||
|
) -> &'tcx ty::TypeckResults<'tcx> {
|
||||||
|
// Closures' typeck results come from their outermost function,
|
||||||
|
// as they are part of the same "inference environment".
|
||||||
|
let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
|
||||||
|
if typeck_root_def_id != def_id {
|
||||||
|
return tcx.typeck(typeck_root_def_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||||
|
let span = tcx.hir().span(id);
|
||||||
|
|
||||||
|
// Figure out what primary body this item has.
|
||||||
|
let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
|
||||||
|
span_bug!(span, "can't type-check body of {:?}", def_id);
|
||||||
|
});
|
||||||
|
let body = tcx.hir().body(body_id);
|
||||||
|
|
||||||
|
let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
|
||||||
|
let param_env = tcx.param_env(def_id);
|
||||||
|
let mut fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
|
||||||
|
let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
|
||||||
|
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
|
||||||
|
<dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
|
||||||
|
} else {
|
||||||
|
tcx.fn_sig(def_id)
|
||||||
|
};
|
||||||
|
|
||||||
|
check_abi(tcx, id, span, fn_sig.abi());
|
||||||
|
|
||||||
|
// Compute the function signature from point of view of inside the fn.
|
||||||
|
let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
|
||||||
|
let fn_sig = inh.normalize_associated_types_in(
|
||||||
|
body.value.span,
|
||||||
|
body_id.hir_id,
|
||||||
|
param_env,
|
||||||
|
fn_sig,
|
||||||
|
);
|
||||||
|
check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
|
||||||
|
} else {
|
||||||
|
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
|
||||||
|
let expected_type = body_ty
|
||||||
|
.and_then(|ty| match ty.kind {
|
||||||
|
hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| match tcx.hir().get(id) {
|
||||||
|
Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
|
||||||
|
Node::Expr(&hir::Expr {
|
||||||
|
kind: hir::ExprKind::ConstBlock(ref anon_const),
|
||||||
|
..
|
||||||
|
}) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
|
||||||
|
kind: TypeVariableOriginKind::TypeInference,
|
||||||
|
span,
|
||||||
|
}),
|
||||||
|
Node::Ty(&hir::Ty {
|
||||||
|
kind: hir::TyKind::Typeof(ref anon_const), ..
|
||||||
|
}) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
|
||||||
|
kind: TypeVariableOriginKind::TypeInference,
|
||||||
|
span,
|
||||||
|
}),
|
||||||
|
Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
|
||||||
|
| Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
|
||||||
|
let operand_ty = asm
|
||||||
|
.operands
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(op, _op_sp)| match op {
|
||||||
|
hir::InlineAsmOperand::Const { anon_const }
|
||||||
|
if anon_const.hir_id == id =>
|
||||||
|
{
|
||||||
|
// Inline assembly constants must be integers.
|
||||||
|
Some(fcx.next_int_var())
|
||||||
|
}
|
||||||
|
hir::InlineAsmOperand::SymFn { anon_const }
|
||||||
|
if anon_const.hir_id == id =>
|
||||||
|
{
|
||||||
|
Some(fcx.next_ty_var(TypeVariableOrigin {
|
||||||
|
kind: TypeVariableOriginKind::MiscVariable,
|
||||||
|
span,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.next();
|
||||||
|
operand_ty.unwrap_or_else(fallback)
|
||||||
|
}
|
||||||
|
_ => fallback(),
|
||||||
|
},
|
||||||
|
_ => fallback(),
|
||||||
|
});
|
||||||
|
|
||||||
|
let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
|
||||||
|
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
|
||||||
|
|
||||||
|
// Gather locals in statics (because of block expressions).
|
||||||
|
GatherLocalsVisitor::new(&fcx).visit_body(body);
|
||||||
|
|
||||||
|
fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
|
||||||
|
|
||||||
|
fcx.write_ty(id, expected_type);
|
||||||
|
|
||||||
|
fcx
|
||||||
|
};
|
||||||
|
|
||||||
|
let fallback_has_occurred = fcx.type_inference_fallback();
|
||||||
|
|
||||||
|
// Even though coercion casts provide type hints, we check casts after fallback for
|
||||||
|
// backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
|
||||||
|
fcx.check_casts();
|
||||||
|
fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
|
||||||
|
|
||||||
|
// Closure and generator analysis may run after fallback
|
||||||
|
// because they don't constrain other type variables.
|
||||||
|
// Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now)
|
||||||
|
let prev_constness = fcx.param_env.constness();
|
||||||
|
fcx.param_env = fcx.param_env.without_const();
|
||||||
|
fcx.closure_analyze(body);
|
||||||
|
fcx.param_env = fcx.param_env.with_constness(prev_constness);
|
||||||
|
assert!(fcx.deferred_call_resolutions.borrow().is_empty());
|
||||||
|
// Before the generator analysis, temporary scopes shall be marked to provide more
|
||||||
|
// precise information on types to be captured.
|
||||||
|
fcx.resolve_rvalue_scopes(def_id.to_def_id());
|
||||||
|
fcx.resolve_generator_interiors(def_id.to_def_id());
|
||||||
|
|
||||||
|
for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
|
||||||
|
let ty = fcx.normalize_ty(span, ty);
|
||||||
|
fcx.require_type_is_sized(ty, span, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
fcx.select_all_obligations_or_error();
|
||||||
|
|
||||||
|
if !fcx.infcx.is_tainted_by_errors() {
|
||||||
|
fcx.check_transmutes();
|
||||||
|
}
|
||||||
|
|
||||||
|
fcx.check_asms();
|
||||||
|
|
||||||
|
fcx.infcx.skip_region_resolution();
|
||||||
|
|
||||||
|
fcx.resolve_type_vars_in_body(body)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Consistency check our TypeckResults instance can hold all ItemLocalIds
|
||||||
|
// it will need to hold.
|
||||||
|
assert_eq!(typeck_results.hir_owner, id.owner);
|
||||||
|
|
||||||
|
typeck_results
|
||||||
|
}
|
||||||
|
|
||||||
|
/// When `check_fn` is invoked on a generator (i.e., a body that
|
||||||
|
/// includes yield), it returns back some information about the yield
|
||||||
|
/// points.
|
||||||
|
struct GeneratorTypes<'tcx> {
|
||||||
|
/// Type of generator argument / values returned by `yield`.
|
||||||
|
resume_ty: Ty<'tcx>,
|
||||||
|
|
||||||
|
/// Type of value that is yielded.
|
||||||
|
yield_ty: Ty<'tcx>,
|
||||||
|
|
||||||
|
/// Types that are captured (see `GeneratorInterior` for more).
|
||||||
|
interior: Ty<'tcx>,
|
||||||
|
|
||||||
|
/// Indicates if the generator is movable or static (immovable).
|
||||||
|
movability: hir::Movability,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum Needs {
|
||||||
|
MutPlace,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Needs {
|
||||||
|
fn maybe_mut_place(m: hir::Mutability) -> Self {
|
||||||
|
match m {
|
||||||
|
hir::Mutability::Mut => Needs::MutPlace,
|
||||||
|
hir::Mutability::Not => Needs::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub enum PlaceOp {
|
||||||
|
Deref,
|
||||||
|
Index,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BreakableCtxt<'tcx> {
|
||||||
|
may_break: bool,
|
||||||
|
|
||||||
|
// this is `null` for loops where break with a value is illegal,
|
||||||
|
// such as `while`, `for`, and `while let`
|
||||||
|
coerce: Option<DynamicCoerceMany<'tcx>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EnclosingBreakables<'tcx> {
|
||||||
|
stack: Vec<BreakableCtxt<'tcx>>,
|
||||||
|
by_id: HirIdMap<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> EnclosingBreakables<'tcx> {
|
||||||
|
fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
|
||||||
|
self.opt_find_breakable(target_id).unwrap_or_else(|| {
|
||||||
|
bug!("could not find enclosing breakable with id {}", target_id);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
|
||||||
|
match self.by_id.get(&target_id) {
|
||||||
|
Some(ix) => Some(&mut self.stack[*ix]),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) {
|
||||||
|
struct_span_err!(
|
||||||
|
tcx.sess,
|
||||||
|
span,
|
||||||
|
E0533,
|
||||||
|
"expected unit struct, unit variant or constant, found {} `{}`",
|
||||||
|
res.descr(),
|
||||||
|
rustc_hir_pretty::qpath_to_string(qpath),
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Controls whether the arguments are tupled. This is used for the call
|
||||||
|
/// operator.
|
||||||
|
///
|
||||||
|
/// Tupling means that all call-side arguments are packed into a tuple and
|
||||||
|
/// passed as a single parameter. For example, if tupling is enabled, this
|
||||||
|
/// function:
|
||||||
|
/// ```
|
||||||
|
/// fn f(x: (isize, isize)) {}
|
||||||
|
/// ```
|
||||||
|
/// Can be called as:
|
||||||
|
/// ```ignore UNSOLVED (can this be done in user code?)
|
||||||
|
/// # fn f(x: (isize, isize)) {}
|
||||||
|
/// f(1, 2);
|
||||||
|
/// ```
|
||||||
|
/// Instead of:
|
||||||
|
/// ```
|
||||||
|
/// # fn f(x: (isize, isize)) {}
|
||||||
|
/// f((1, 2));
|
||||||
|
/// ```
|
||||||
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
|
enum TupleArgumentsFlag {
|
||||||
|
DontTupleArguments,
|
||||||
|
TupleArguments,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fatally_break_rust(sess: &Session) {
|
||||||
|
let handler = sess.diagnostic();
|
||||||
|
handler.span_bug_no_panic(
|
||||||
|
MultiSpan::new(),
|
||||||
|
"It looks like you're trying to break rust; would you like some ICE?",
|
||||||
|
);
|
||||||
|
handler.note_without_error("the compiler expectedly panicked. this is a feature.");
|
||||||
|
handler.note_without_error(
|
||||||
|
"we would appreciate a joke overview: \
|
||||||
|
https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
|
||||||
|
);
|
||||||
|
handler.note_without_error(&format!(
|
||||||
|
"rustc {} running on {}",
|
||||||
|
option_env!("CFG_VERSION").unwrap_or("unknown_version"),
|
||||||
|
config::host_triple(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_expected_num_generic_args<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
trait_did: Option<DefId>,
|
||||||
|
expected: usize,
|
||||||
|
) -> bool {
|
||||||
|
trait_did.map_or(true, |trait_did| {
|
||||||
|
let generics = tcx.generics_of(trait_did);
|
||||||
|
generics.count() == expected + if generics.has_self { 1 } else { 0 }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn provide(providers: &mut Providers) {
|
||||||
|
method::provide(providers);
|
||||||
|
*providers = Providers {
|
||||||
|
typeck_item_bodies,
|
||||||
|
typeck_const_arg,
|
||||||
|
typeck,
|
||||||
|
diagnostic_only_typeck,
|
||||||
|
has_typeck_results,
|
||||||
|
used_trait_imports,
|
||||||
|
..*providers
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
use super::{probe, MethodCallee};
|
use super::{probe, MethodCallee};
|
||||||
|
|
||||||
use crate::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
|
use crate::{callee, FnCtxt};
|
||||||
use crate::check::{callee, FnCtxt};
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::GenericArg;
|
use rustc_hir::GenericArg;
|
||||||
|
use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
|
||||||
use rustc_infer::infer::{self, InferOk};
|
use rustc_infer::infer::{self, InferOk};
|
||||||
use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
|
use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
|
||||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
|
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
|
||||||
|
|
|
@ -10,14 +10,14 @@ mod suggest;
|
||||||
pub use self::suggest::SelfSource;
|
pub use self::suggest::SelfSource;
|
||||||
pub use self::MethodError::*;
|
pub use self::MethodError::*;
|
||||||
|
|
||||||
use crate::check::{Expectation, FnCtxt};
|
use crate::{Expectation, FnCtxt};
|
||||||
use crate::ObligationCause;
|
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_errors::{Applicability, Diagnostic};
|
use rustc_errors::{Applicability, Diagnostic};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{CtorOf, DefKind, Namespace};
|
use rustc_hir::def::{CtorOf, DefKind, Namespace};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_infer::infer::{self, InferOk};
|
use rustc_infer::infer::{self, InferOk};
|
||||||
|
use rustc_middle::traits::ObligationCause;
|
||||||
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
|
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
|
||||||
use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TypeVisitable};
|
use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TypeVisitable};
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
use crate::{
|
||||||
|
method::probe::{self, Pick},
|
||||||
|
FnCtxt,
|
||||||
|
};
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use hir::HirId;
|
use hir::HirId;
|
||||||
use hir::ItemKind;
|
use hir::ItemKind;
|
||||||
|
@ -12,11 +16,6 @@ use rustc_span::symbol::{sym, Ident};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
|
|
||||||
use crate::check::{
|
|
||||||
method::probe::{self, Pick},
|
|
||||||
FnCtxt,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
pub(super) fn lint_dot_call_from_2018(
|
pub(super) fn lint_dot_call_from_2018(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -3,14 +3,12 @@ use super::CandidateSource;
|
||||||
use super::MethodError;
|
use super::MethodError;
|
||||||
use super::NoMatchData;
|
use super::NoMatchData;
|
||||||
|
|
||||||
use crate::check::FnCtxt;
|
|
||||||
use crate::errors::MethodCallOnUnknownType;
|
use crate::errors::MethodCallOnUnknownType;
|
||||||
use crate::hir::def::DefKind;
|
use crate::FnCtxt;
|
||||||
use crate::hir::def_id::DefId;
|
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def::Namespace;
|
use rustc_hir::def::Namespace;
|
||||||
use rustc_infer::infer::canonical::OriginalQueryValues;
|
use rustc_infer::infer::canonical::OriginalQueryValues;
|
||||||
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
|
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
|
||||||
|
@ -23,6 +21,7 @@ use rustc_middle::ty::GenericParamDefKind;
|
||||||
use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitable};
|
use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitable};
|
||||||
use rustc_middle::ty::{InternalSubsts, SubstsRef};
|
use rustc_middle::ty::{InternalSubsts, SubstsRef};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
|
use rustc_span::def_id::DefId;
|
||||||
use rustc_span::def_id::LocalDefId;
|
use rustc_span::def_id::LocalDefId;
|
||||||
use rustc_span::lev_distance::{
|
use rustc_span::lev_distance::{
|
||||||
find_best_match_for_name_with_substrings, lev_distance_with_substrings,
|
find_best_match_for_name_with_substrings, lev_distance_with_substrings,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
//! Give useful errors and suggestions to users when an item can't be
|
//! Give useful errors and suggestions to users when an item can't be
|
||||||
//! found or is otherwise invalid.
|
//! found or is otherwise invalid.
|
||||||
|
|
||||||
use crate::check::FnCtxt;
|
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
|
use crate::FnCtxt;
|
||||||
use rustc_ast::ast::Mutability;
|
use rustc_ast::ast::Mutability;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use super::method::MethodCallee;
|
use super::method::MethodCallee;
|
||||||
use super::{has_expected_num_generic_args, FnCtxt};
|
use super::{has_expected_num_generic_args, FnCtxt};
|
||||||
use crate::check::Expectation;
|
use crate::Expectation;
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_errors::{self, struct_span_err, Applicability, Diagnostic};
|
use rustc_errors::{self, struct_span_err, Applicability, Diagnostic};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::check::FnCtxt;
|
use crate::FnCtxt;
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::check::method::MethodCallee;
|
use crate::method::MethodCallee;
|
||||||
use crate::check::{has_expected_num_generic_args, FnCtxt, PlaceOp};
|
use crate::{has_expected_num_generic_args, FnCtxt, PlaceOp};
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// unresolved type variables and replaces "ty_var" types with their
|
// unresolved type variables and replaces "ty_var" types with their
|
||||||
// substitutions.
|
// substitutions.
|
||||||
|
|
||||||
use crate::check::FnCtxt;
|
use crate::FnCtxt;
|
||||||
use hir::def_id::LocalDefId;
|
use hir::def_id::LocalDefId;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
|
|
|
@ -38,6 +38,7 @@ rustc_mir_transform = { path = "../rustc_mir_transform" }
|
||||||
rustc_monomorphize = { path = "../rustc_monomorphize" }
|
rustc_monomorphize = { path = "../rustc_monomorphize" }
|
||||||
rustc_passes = { path = "../rustc_passes" }
|
rustc_passes = { path = "../rustc_passes" }
|
||||||
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
|
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
|
||||||
|
rustc_hir_typeck = { path = "../rustc_hir_typeck" }
|
||||||
rustc_lint = { path = "../rustc_lint" }
|
rustc_lint = { path = "../rustc_lint" }
|
||||||
rustc_errors = { path = "../rustc_errors" }
|
rustc_errors = { path = "../rustc_errors" }
|
||||||
rustc_plugin_impl = { path = "../rustc_plugin_impl" }
|
rustc_plugin_impl = { path = "../rustc_plugin_impl" }
|
||||||
|
|
|
@ -736,6 +736,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
|
||||||
rustc_monomorphize::provide(providers);
|
rustc_monomorphize::provide(providers);
|
||||||
rustc_privacy::provide(providers);
|
rustc_privacy::provide(providers);
|
||||||
rustc_hir_analysis::provide(providers);
|
rustc_hir_analysis::provide(providers);
|
||||||
|
rustc_hir_typeck::provide(providers);
|
||||||
ty::provide(providers);
|
ty::provide(providers);
|
||||||
traits::provide(providers);
|
traits::provide(providers);
|
||||||
rustc_passes::provide(providers);
|
rustc_passes::provide(providers);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue