diff options
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 136 |
1 files changed, 74 insertions, 62 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 60fec05d3..2d841d53f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -5,11 +5,11 @@ use crate::method::MethodCallee; use crate::Expectation::*; use crate::TupleArgumentsFlag::*; use crate::{ - struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs, + struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs, RawTy, TupleArgumentsFlag, }; use rustc_ast as ast; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticId, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; @@ -28,7 +28,7 @@ use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty, TypeSuperVisitable, TypeVisitor}; use rustc_session::Session; -use rustc_span::symbol::Ident; +use rustc_span::symbol::{kw, Ident}; use rustc_span::{self, sym, Span}; use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; @@ -214,7 +214,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "cannot use call notation; the first type parameter \ for the function trait is neither a tuple nor unit" ) - .delay_as_bug(); + .emit(); (self.err_args(provided_args.len()), None) } } @@ -473,7 +473,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr: &hir::Expr<'tcx>, ) { // Next, let's construct the error - let (error_span, full_call_span, ctor_of, is_method) = match &call_expr.kind { + let (error_span, full_call_span, call_name, is_method) = match &call_expr.kind { hir::ExprKind::Call( hir::Expr { hir_id, span, kind: hir::ExprKind::Path(qpath), .. }, _, @@ -481,12 +481,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Res::Def(DefKind::Ctor(of, _), _) = self.typeck_results.borrow().qpath_res(qpath, *hir_id) { - (call_span, *span, Some(of), false) + let name = match of { + CtorOf::Struct => "struct", + CtorOf::Variant => "enum variant", + }; + (call_span, *span, name, false) } else { - (call_span, *span, None, false) + (call_span, *span, "function", false) } } - hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None, false), + hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, "function", false), hir::ExprKind::MethodCall(path_segment, _, _, span) => { let ident_span = path_segment.ident.span; let ident_span = if let Some(args) = path_segment.args { @@ -494,17 +498,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { ident_span }; - // methods are never ctors - (*span, ident_span, None, true) + (*span, ident_span, "method", true) } k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k), }; let args_span = error_span.trim_start(full_call_span).unwrap_or(error_span); - let call_name = match ctor_of { - Some(CtorOf::Struct) => "struct", - Some(CtorOf::Variant) => "enum variant", - None => "function", - }; // Don't print if it has error types or is just plain `_` fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool { @@ -690,8 +688,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err = tcx.sess.struct_span_err_with_code( full_call_span, &format!( - "this {} takes {}{} but {} {} supplied", - call_name, + "{call_name} takes {}{} but {} {} supplied", if c_variadic { "at least " } else { "" }, potentially_plural_count( formal_and_expected_inputs.len(), @@ -1013,7 +1010,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { args_span }; - labels.push((span, format!("multiple arguments are missing"))); + labels.push((span, "multiple arguments are missing".to_string())); suggestion_text = match suggestion_text { SuggestionText::None | SuggestionText::Provide(_) => { SuggestionText::Provide(true) @@ -1141,6 +1138,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "()".to_string() } else if expected_ty.is_suggestable(tcx, false) { format!("/* {} */", expected_ty) + } else if let Some(fn_def_id) = fn_def_id + && self.tcx.def_kind(fn_def_id).is_fn_like() + && let self_implicit = matches!(call_expr.kind, hir::ExprKind::MethodCall(..)) as usize + && let Some(arg) = self.tcx.fn_arg_names(fn_def_id).get(expected_idx.as_usize() + self_implicit) + && arg.name != kw::SelfLower + { + format!("/* {} */", arg.name) } else { "/* value */".to_string() } @@ -1169,7 +1173,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match lit.node { ast::LitKind::Str(..) => tcx.mk_static_str(), - ast::LitKind::ByteStr(ref v) => { + ast::LitKind::ByteStr(ref v, _) => { tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64)) } ast::LitKind::Byte(_) => tcx.types.u8, @@ -1215,31 +1219,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); return None; } - Res::Def(DefKind::Variant, _) => match ty.kind() { - ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did(), substs)), - _ => bug!("unexpected type: {:?}", ty), + Res::Def(DefKind::Variant, _) => match ty.normalized.ty_adt_def() { + Some(adt) => { + Some((adt.variant_of_res(def), adt.did(), Self::user_substs_for_adt(ty))) + } + _ => bug!("unexpected type: {:?}", ty.normalized), }, Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) | Res::SelfTyParam { .. } - | Res::SelfTyAlias { .. } => match ty.kind() { - ty::Adt(adt, substs) if !adt.is_enum() => { - Some((adt.non_enum_variant(), adt.did(), substs)) + | Res::SelfTyAlias { .. } => match ty.normalized.ty_adt_def() { + Some(adt) if !adt.is_enum() => { + Some((adt.non_enum_variant(), adt.did(), Self::user_substs_for_adt(ty))) } _ => None, }, _ => bug!("unexpected definition: {:?}", def), }; - if let Some((variant, did, substs)) = variant { + if let Some((variant, did, ty::UserSubsts { substs, user_self_ty })) = variant { debug!("check_struct_path: did={:?} substs={:?}", did, substs); - self.write_user_type_annotation_from_substs(hir_id, did, substs, None); + + // Register type annotation. + self.write_user_type_annotation_from_substs(hir_id, did, substs, user_self_ty); // Check bounds on type arguments used in the path. self.add_required_obligations_for_hir(path_span, did, substs, hir_id); - Some((variant, ty)) + Some((variant, ty.normalized)) } else { - match ty.kind() { + match ty.normalized.kind() { ty::Error(_) => { // E0071 might be caused by a spelling error, which will have // already caused an error message and probably a suggestion @@ -1252,7 +1260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { path_span, E0071, "expected struct, variant or union type, found {}", - ty.sort_string(self.tcx) + ty.normalized.sort_string(self.tcx) ) .span_label(path_span, "not a struct") .emit(); @@ -1300,7 +1308,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type check the initializer. if let Some(ref init) = decl.init { let init_ty = self.check_decl_initializer(decl.hir_id, decl.pat, &init); - self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, init_ty); + self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, init_ty); } // Does the expected pattern type originate from an expression and what is the span? @@ -1315,7 +1323,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type check the pattern. Override if necessary to avoid knock-on errors. self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr); let pat_ty = self.node_ty(decl.pat.hir_id); - self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, pat_ty); + self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, pat_ty); if let Some(blk) = decl.els { let previous_diverges = self.diverges.get(); @@ -1620,14 +1628,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, hir_id: hir::HirId, pat: &'tcx hir::Pat<'tcx>, - decl_ty: Ty<'tcx>, ty: Ty<'tcx>, ) { if ty.references_error() { // Override the types everywhere with `err()` to avoid knock on errors. - self.write_ty(hir_id, ty); - self.write_ty(pat.hir_id, ty); - let local_ty = LocalTy { decl_ty, revealed_ty: ty }; + let err = self.tcx.ty_error(); + self.write_ty(hir_id, err); + self.write_ty(pat.hir_id, err); + let local_ty = LocalTy { decl_ty: err, revealed_ty: err }; self.locals.borrow_mut().insert(hir_id, local_ty); self.locals.borrow_mut().insert(pat.hir_id, local_ty); } @@ -1640,20 +1648,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { qpath: &QPath<'_>, path_span: Span, hir_id: hir::HirId, - ) -> (Res, Ty<'tcx>) { + ) -> (Res, RawTy<'tcx>) { match *qpath { QPath::Resolved(ref maybe_qself, ref path) => { - let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself)); - let ty = <dyn AstConv<'_>>::res_to_ty(self, self_ty, path, true); - (path.res, ty) + let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself).raw); + let ty = self.astconv().res_to_ty(self_ty, path, true); + (path.res, self.handle_raw_ty(path_span, ty)) } QPath::TypeRelative(ref qself, ref segment) => { let ty = self.to_ty(qself); - let result = <dyn AstConv<'_>>::associated_path_to_ty( - self, hir_id, path_span, ty, qself, segment, true, - ); + let result = self + .astconv() + .associated_path_to_ty(hir_id, path_span, ty.raw, qself, segment, true); let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error()); + let ty = self.handle_raw_ty(path_span, ty); let result = result.map(|(_, kind, def_id)| (kind, def_id)); // Write back the new resolution. @@ -1662,7 +1671,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty) } QPath::LangItem(lang_item, span, id) => { - self.resolve_lang_item_path(lang_item, span, hir_id, id) + let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id, id); + (res, self.handle_raw_ty(path_span, ty)) } } } @@ -1682,7 +1692,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // even if their `ObligationCauseCode` isn't an `Expr*Obligation` kind. // This is important since if we adjust one span but not the other, then // we will have "duplicated" the error on the UI side. - let mut remap_cause = FxHashSet::default(); + let mut remap_cause = FxIndexSet::default(); let mut not_adjusted = vec![]; for error in errors { @@ -1710,6 +1720,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + // Adjust any other errors that come from other cause codes, when these + // errors are of the same predicate as one we successfully adjusted, and + // when their spans overlap (suggesting they're due to the same root cause). + // + // This is because due to normalization, we often register duplicate + // obligations with misc obligations that are basically impossible to + // line back up with a useful ExprBindingObligation. for error in not_adjusted { for (span, predicate, cause) in &remap_cause { if *predicate == error.obligation.predicate @@ -1796,7 +1813,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir_id: call_hir_id, span: call_span, .. - }) = hir.get(hir.get_parent_node(expr.hir_id)) + }) = hir.get_parent(expr.hir_id) && callee.hir_id == expr.hir_id { if self.closure_span_overlaps_error(error, *call_span) { @@ -2111,8 +2128,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME(compiler-errors): This could be problematic if something has two // fn-like predicates with different args, but callable types really never // do that, so it's OK. - for (predicate, span) in - std::iter::zip(instantiated.predicates, instantiated.spans) + for (predicate, span) in instantiated { if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = predicate.kind().skip_binder() && pred.self_ty().peel_refs() == callee_ty @@ -2124,7 +2140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - ty::Opaque(new_def_id, _) + ty::Alias(ty::Opaque, ty::AliasTy { def_id: new_def_id, .. }) | ty::Closure(new_def_id, _) | ty::FnDef(new_def_id, _) => { def_id = new_def_id; @@ -2132,19 +2148,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => { // Look for a user-provided impl of a `Fn` trait, and point to it. let new_def_id = self.probe(|_| { - let trait_ref = ty::TraitRef::new( + let trait_ref = self.tcx.mk_trait_ref( call_kind.to_def_id(self.tcx), - self.tcx.mk_substs( - [ - ty::GenericArg::from(callee_ty), - self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: rustc_span::DUMMY_SP, - }) - .into(), - ] - .into_iter(), - ), + [ + callee_ty, + self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: rustc_span::DUMMY_SP, + }), + ], ); let obligation = traits::Obligation::new( self.tcx, @@ -2217,7 +2229,7 @@ fn find_param_in_ty<'tcx>(ty: Ty<'tcx>, param_to_point_at: ty::GenericArg<'tcx>) if arg == param_to_point_at { return true; } else if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Projection(..) = ty.kind() + && let ty::Alias(ty::Projection, ..) = ty.kind() { // This logic may seem a bit strange, but typically when // we have a projection type in a function signature, the |