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",
|
||||
]
|
||||
|
||||
[[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]]
|
||||
name = "rustc_incremental"
|
||||
version = "0.0.0"
|
||||
|
@ -3637,6 +3663,7 @@ dependencies = [
|
|||
"rustc_expand",
|
||||
"rustc_hir",
|
||||
"rustc_hir_analysis",
|
||||
"rustc_hir_typeck",
|
||||
"rustc_incremental",
|
||||
"rustc_lint",
|
||||
"rustc_macros",
|
||||
|
|
|
@ -582,7 +582,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
assoc_bindings
|
||||
}
|
||||
|
||||
pub(crate) fn create_substs_for_associated_item(
|
||||
pub fn create_substs_for_associated_item(
|
||||
&self,
|
||||
span: Span,
|
||||
item_def_id: DefId,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::check::intrinsicck::InlineAsmCtxt;
|
||||
|
||||
use super::coercion::CoerceMany;
|
||||
use super::compare_method::check_type_bounds;
|
||||
use super::compare_method::{compare_impl_method, compare_ty_impl};
|
||||
use super::*;
|
||||
|
@ -10,10 +9,8 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{ItemKind, Node, PathSegment};
|
||||
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::traits::Obligation;
|
||||
use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
|
||||
|
@ -34,7 +31,7 @@ use rustc_trait_selection::traits::{self, ObligationCtxt};
|
|||
|
||||
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) {
|
||||
Some(true) => (),
|
||||
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) {
|
||||
let def = tcx.adt_def(def_id);
|
||||
let span = tcx.def_span(def_id);
|
||||
|
|
|
@ -1,117 +1,11 @@
|
|||
use hir::HirId;
|
||||
use rustc_ast::InlineAsmTemplatePiece;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
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, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::{Symbol, DUMMY_SP};
|
||||
use rustc_target::abi::{Pointer, VariantIdx};
|
||||
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> {
|
||||
tcx: TyCtxt<'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 closure;
|
||||
pub mod coercion;
|
||||
mod compare_method;
|
||||
pub mod demand;
|
||||
mod diverges;
|
||||
pub mod dropck;
|
||||
mod expectation;
|
||||
mod expr;
|
||||
mod fallback;
|
||||
mod fn_ctxt;
|
||||
mod gather_locals;
|
||||
mod generator_interior;
|
||||
mod inherited;
|
||||
pub mod intrinsic;
|
||||
mod intrinsicck;
|
||||
pub mod method;
|
||||
mod op;
|
||||
mod pat;
|
||||
mod place_op;
|
||||
pub mod intrinsicck;
|
||||
mod region;
|
||||
pub mod rvalue_scopes;
|
||||
mod upvar;
|
||||
pub mod wfcheck;
|
||||
pub mod writeback;
|
||||
|
||||
use check::{check_abi, check_fn, check_mod_item_types};
|
||||
pub use diverges::Diverges;
|
||||
pub use expectation::Expectation;
|
||||
pub use fn_ctxt::*;
|
||||
pub use inherited::{Inherited, InheritedBuilder};
|
||||
pub use check::check_abi;
|
||||
|
||||
use crate::astconv::AstConv;
|
||||
use crate::check::gather_locals::GatherLocalsVisitor;
|
||||
use check::check_mod_item_types;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::{
|
||||
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan,
|
||||
};
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
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_session::config;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::DUMMY_SP;
|
||||
use rustc_span::symbol::{kw, Ident};
|
||||
use rustc_span::{self, BytePos, Span, Symbol};
|
||||
use rustc_target::abi::VariantIdx;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits;
|
||||
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
|
||||
use std::cell::RefCell;
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use crate::require_c_abi_if_c_variadic;
|
||||
use crate::util::common::indenter;
|
||||
|
||||
use self::coercion::DynamicCoerceMany;
|
||||
use self::compare_method::collect_trait_impl_trait_tys;
|
||||
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) {
|
||||
method::provide(providers);
|
||||
wfcheck::provide(providers);
|
||||
*providers = Providers {
|
||||
typeck_item_bodies,
|
||||
typeck_const_arg,
|
||||
typeck,
|
||||
diagnostic_only_typeck,
|
||||
has_typeck_results,
|
||||
adt_destructor,
|
||||
used_trait_imports,
|
||||
check_mod_item_types,
|
||||
region_scope_tree,
|
||||
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)
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// expressions.
|
||||
fn get_owner_return_paths<'tcx>(
|
||||
|
@ -528,9 +129,10 @@ fn get_owner_return_paths<'tcx>(
|
|||
})
|
||||
}
|
||||
|
||||
// Forbid defining intrinsics in Rust code,
|
||||
// as they must always be defined by the compiler.
|
||||
fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
|
||||
/// Forbid defining intrinsics in Rust code,
|
||||
/// as they must always be defined by the compiler.
|
||||
// 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 {
|
||||
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!() }}")
|
||||
}
|
||||
|
||||
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.
|
||||
/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
|
||||
/// 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::Const => {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -896,76 +509,7 @@ fn bad_non_zero_sized_fields<'tcx>(
|
|||
err.emit();
|
||||
}
|
||||
|
||||
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 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 {
|
||||
// FIXME: Consider moving this method to a more fitting place.
|
||||
pub fn potentially_plural_count(count: usize, word: &str) -> String {
|
||||
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::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler};
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic};
|
||||
use rustc_middle::ty::Ty;
|
||||
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)]
|
||||
#[diag(hir_analysis::unrecognized_atomic_operation, code = "E0092")]
|
||||
pub struct UnrecognizedAtomicOperation<'a> {
|
||||
|
@ -124,13 +113,6 @@ pub struct AssocTypeBindingNotAllowed {
|
|||
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::typeof_reserved_keyword_used, code = "E0516")]
|
||||
pub struct TypeofReservedKeywordUsed<'tcx> {
|
||||
|
@ -142,39 +124,6 @@ pub struct TypeofReservedKeywordUsed<'tcx> {
|
|||
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)]
|
||||
#[diag(hir_analysis::value_of_associated_struct_already_specified, code = "E0719")]
|
||||
pub struct ValueOfAssociatedStructAlreadySpecified {
|
||||
|
@ -187,52 +136,6 @@ pub struct ValueOfAssociatedStructAlreadySpecified {
|
|||
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)]
|
||||
#[diag(hir_analysis::unconstrained_opaque_type)]
|
||||
#[note]
|
||||
|
@ -346,29 +249,3 @@ pub struct ExpectedUsedSymbol {
|
|||
#[primary_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.
|
||||
pub mod check;
|
||||
pub mod expr_use_visitor;
|
||||
|
||||
mod astconv;
|
||||
pub mod astconv;
|
||||
mod bounds;
|
||||
mod check_unused;
|
||||
mod coherence;
|
||||
mod collect;
|
||||
// FIXME: This module shouldn't be public.
|
||||
pub mod collect;
|
||||
mod constrained_generic_params;
|
||||
mod errors;
|
||||
pub mod hir_wf_check;
|
||||
mod impl_wf_check;
|
||||
mod mem_categorization;
|
||||
mod outlives;
|
||||
mod structured_errors;
|
||||
pub mod structured_errors;
|
||||
mod variance;
|
||||
|
||||
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::check::{Diverges, Expectation, FnCtxt, Needs};
|
||||
use crate::coercion::{AsCoercionSite, CoerceMany};
|
||||
use crate::{Diverges, Expectation, FnCtxt, Needs};
|
||||
use rustc_errors::{Applicability, MultiSpan};
|
||||
use rustc_hir::{self as hir, ExprKind};
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use super::method::probe::{IsSuggestion, Mode, ProbeScope};
|
||||
use super::method::MethodCallee;
|
||||
use super::{Expectation, FnCtxt, TupleArgumentsFlag};
|
||||
use crate::type_error_struct;
|
||||
|
||||
use crate::type_error_struct;
|
||||
use rustc_ast::util::parser::PREC_POSTFIX;
|
||||
use rustc_errors::{struct_span_err, Applicability, Diagnostic, StashKey};
|
||||
use rustc_hir as hir;
|
||||
|
|
|
@ -30,9 +30,7 @@
|
|||
|
||||
use super::FnCtxt;
|
||||
|
||||
use crate::hir::def_id::DefId;
|
||||
use crate::type_error_struct;
|
||||
use hir::def_id::LOCAL_CRATE;
|
||||
use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
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_session::lint;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
|
@ -527,7 +526,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
err.emit();
|
||||
}
|
||||
CastError::SizedUnsizedCast => {
|
||||
use crate::structured_errors::{SizedUnsizedCast, StructuredDiagnostic};
|
||||
use rustc_hir_analysis::structured_errors::{
|
||||
SizedUnsizedCast, StructuredDiagnostic,
|
||||
};
|
||||
|
||||
SizedUnsizedCast {
|
||||
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 crate::astconv::AstConv;
|
||||
use hir::def::DefKind;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir_analysis::astconv::AstConv;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||
use rustc_infer::infer::{InferOk, InferResult};
|
||||
|
|
|
@ -35,8 +35,7 @@
|
|||
//! // and are then unable to coerce `&7i32` to `&mut i32`.
|
||||
//! ```
|
||||
|
||||
use crate::astconv::AstConv;
|
||||
use crate::check::FnCtxt;
|
||||
use crate::FnCtxt;
|
||||
use rustc_errors::{
|
||||
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::intravisit::{self, Visitor};
|
||||
use rustc_hir::Expr;
|
||||
use rustc_hir_analysis::astconv::AstConv;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::{Coercion, InferOk, InferResult};
|
||||
use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt};
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
use crate::check::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 crate::FnCtxt;
|
||||
use rustc_ast::util::parser::PREC_POSTFIX;
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{is_range_literal, Node};
|
||||
use rustc_infer::infer::InferOk;
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::middle::stability::EvalResult;
|
||||
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::{BytePos, Span};
|
||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::ObligationCause;
|
||||
|
||||
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.
|
||||
|
||||
use crate::astconv::AstConv as _;
|
||||
use crate::check::cast;
|
||||
use crate::check::coercion::CoerceMany;
|
||||
use crate::check::fatally_break_rust;
|
||||
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::cast;
|
||||
use crate::coercion::CoerceMany;
|
||||
use crate::coercion::DynamicCoerceMany;
|
||||
use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
|
||||
use crate::errors::{
|
||||
FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
|
||||
YieldExprOutsideOfGenerator,
|
||||
};
|
||||
use crate::fatally_break_rust;
|
||||
use crate::method::SelfSource;
|
||||
use crate::type_error_struct;
|
||||
|
||||
use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
|
||||
use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
|
||||
use crate::{
|
||||
report_unexpected_variant_res, BreakableCtxt, Diverges, FnCtxt, Needs,
|
||||
TupleArgumentsFlag::DontTupleArguments,
|
||||
};
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
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::lang_items::LangItem;
|
||||
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::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::InferOk;
|
||||
|
@ -1362,7 +1363,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// Create a new function context.
|
||||
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);
|
||||
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,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum MutateMode {
|
||||
Init,
|
||||
/// Example: `x = y`
|
||||
JustWrite,
|
||||
/// Example: `x += y`
|
||||
WriteAndRead,
|
||||
}
|
||||
|
||||
/// The ExprUseVisitor type
|
||||
///
|
||||
/// This is the code that actually walks the tree.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::check::FnCtxt;
|
||||
use crate::FnCtxt;
|
||||
use rustc_data_structures::{
|
||||
fx::{FxHashMap, FxHashSet},
|
||||
graph::WithSuccessors,
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
use crate::astconv::{
|
||||
AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
|
||||
GenericArgCountResult, IsMethodCall, PathSeg,
|
||||
};
|
||||
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 crate::callee::{self, DeferredCallResolution};
|
||||
use crate::method::{self, MethodCallee, SelfSource};
|
||||
use crate::rvalue_scopes;
|
||||
use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
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::lang_items::LangItem;
|
||||
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::error_reporting::TypeAnnotationNeeded::E0282;
|
||||
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();
|
||||
for (body_id, interior, kind) in generators.drain(..) {
|
||||
self.select_obligations_where_possible(false, |_| {});
|
||||
crate::check::generator_interior::resolve_interior(
|
||||
self, def_id, body_id, interior, kind,
|
||||
);
|
||||
crate::generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +1,13 @@
|
|||
use crate::astconv::AstConv;
|
||||
use crate::check::coercion::CoerceMany;
|
||||
use crate::check::fn_ctxt::arg_matrix::{
|
||||
ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx,
|
||||
use crate::coercion::CoerceMany;
|
||||
use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx};
|
||||
use crate::gather_locals::Declaration;
|
||||
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_data_structures::fx::FxHashSet;
|
||||
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_id::DefId;
|
||||
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_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
|
@ -391,7 +389,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
ty: Ty<'tcx>,
|
||||
cast_ty: &str,
|
||||
) {
|
||||
use crate::structured_errors::MissingCastForVariadicArg;
|
||||
use rustc_hir_analysis::structured_errors::MissingCastForVariadicArg;
|
||||
|
||||
MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit();
|
||||
}
|
||||
|
|
|
@ -6,12 +6,11 @@ mod suggestions;
|
|||
pub use _impl::*;
|
||||
pub use suggestions::*;
|
||||
|
||||
use crate::astconv::AstConv;
|
||||
use crate::check::coercion::DynamicCoerceMany;
|
||||
use crate::check::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
|
||||
|
||||
use crate::coercion::DynamicCoerceMany;
|
||||
use crate::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir_analysis::astconv::AstConv;
|
||||
use rustc_infer::infer;
|
||||
use rustc_infer::infer::error_reporting::TypeErrCtxt;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
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_errors::{Applicability, Diagnostic, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
|
@ -10,6 +9,7 @@ use rustc_hir::lang_items::LangItem;
|
|||
use rustc_hir::{
|
||||
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::traits::{self, StatementAsExpression};
|
||||
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::intravisit::{self, Visitor};
|
||||
use rustc_hir::PatKind;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::UserType;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
use self::cfg_build::build_control_flow_graph;
|
||||
use self::record_consumed_borrow::find_consumed_and_borrowed;
|
||||
use crate::check::FnCtxt;
|
||||
use crate::FnCtxt;
|
||||
use hir::def_id::DefId;
|
||||
use hir::{Body, HirId, HirIdMap, Node};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::TrackedValue;
|
||||
use crate::{
|
||||
check::FnCtxt,
|
||||
expr_use_visitor::{self, ExprUseVisitor},
|
||||
FnCtxt,
|
||||
};
|
||||
use hir::{def_id::DefId, Body, HirId, HirIdMap};
|
||||
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 crate::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
|
||||
use crate::check::{callee, FnCtxt};
|
||||
use crate::{callee, FnCtxt};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::GenericArg;
|
||||
use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
|
||||
use rustc_infer::infer::{self, InferOk};
|
||||
use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
|
||||
|
|
|
@ -10,14 +10,14 @@ mod suggest;
|
|||
pub use self::suggest::SelfSource;
|
||||
pub use self::MethodError::*;
|
||||
|
||||
use crate::check::{Expectation, FnCtxt};
|
||||
use crate::ObligationCause;
|
||||
use crate::{Expectation, FnCtxt};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{Applicability, Diagnostic};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Namespace};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::{self, InferOk};
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
|
||||
use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TypeVisitable};
|
||||
use rustc_span::symbol::Ident;
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
use crate::{
|
||||
method::probe::{self, Pick},
|
||||
FnCtxt,
|
||||
};
|
||||
use hir::def_id::DefId;
|
||||
use hir::HirId;
|
||||
use hir::ItemKind;
|
||||
|
@ -12,11 +16,6 @@ use rustc_span::symbol::{sym, Ident};
|
|||
use rustc_span::Span;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
|
||||
use crate::check::{
|
||||
method::probe::{self, Pick},
|
||||
FnCtxt,
|
||||
};
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub(super) fn lint_dot_call_from_2018(
|
||||
&self,
|
||||
|
|
|
@ -3,14 +3,12 @@ use super::CandidateSource;
|
|||
use super::MethodError;
|
||||
use super::NoMatchData;
|
||||
|
||||
use crate::check::FnCtxt;
|
||||
use crate::errors::MethodCallOnUnknownType;
|
||||
use crate::hir::def::DefKind;
|
||||
use crate::hir::def_id::DefId;
|
||||
|
||||
use crate::FnCtxt;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_infer::infer::canonical::OriginalQueryValues;
|
||||
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::{InternalSubsts, SubstsRef};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::lev_distance::{
|
||||
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
|
||||
//! found or is otherwise invalid.
|
||||
|
||||
use crate::check::FnCtxt;
|
||||
use crate::errors;
|
||||
use crate::FnCtxt;
|
||||
use rustc_ast::ast::Mutability;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use super::method::MethodCallee;
|
||||
use super::{has_expected_num_generic_args, FnCtxt};
|
||||
use crate::check::Expectation;
|
||||
use crate::Expectation;
|
||||
use rustc_ast as ast;
|
||||
use rustc_errors::{self, struct_span_err, Applicability, Diagnostic};
|
||||
use rustc_hir as hir;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::check::FnCtxt;
|
||||
use crate::FnCtxt;
|
||||
use rustc_ast as ast;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{
|
||||
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::check::method::MethodCallee;
|
||||
use crate::check::{has_expected_num_generic_args, FnCtxt, PlaceOp};
|
||||
use crate::method::MethodCallee;
|
||||
use crate::{has_expected_num_generic_args, FnCtxt, PlaceOp};
|
||||
use rustc_ast as ast;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// unresolved type variables and replaces "ty_var" types with their
|
||||
// substitutions.
|
||||
|
||||
use crate::check::FnCtxt;
|
||||
use crate::FnCtxt;
|
||||
use hir::def_id::LocalDefId;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
|
|
|
@ -38,6 +38,7 @@ rustc_mir_transform = { path = "../rustc_mir_transform" }
|
|||
rustc_monomorphize = { path = "../rustc_monomorphize" }
|
||||
rustc_passes = { path = "../rustc_passes" }
|
||||
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
|
||||
rustc_hir_typeck = { path = "../rustc_hir_typeck" }
|
||||
rustc_lint = { path = "../rustc_lint" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
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_privacy::provide(providers);
|
||||
rustc_hir_analysis::provide(providers);
|
||||
rustc_hir_typeck::provide(providers);
|
||||
ty::provide(providers);
|
||||
traits::provide(providers);
|
||||
rustc_passes::provide(providers);
|
||||
|
|
Loading…
Add table
Reference in a new issue