diff options
Diffstat (limited to 'compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs')
-rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 105 |
1 files changed, 80 insertions, 25 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index f736f7a96..557950338 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1,10 +1,11 @@ use crate::callee::{self, DeferredCallResolution}; +use crate::errors::CtorIsPrivate; use crate::method::{self, MethodCallee, SelfSource}; use crate::rvalue_scopes; use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, RawTy}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, StashKey}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -35,7 +36,9 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use rustc_target::abi::FieldIdx; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::{self, NormalizeExt, ObligationCauseCode, ObligationCtxt}; +use rustc_trait_selection::traits::{ + self, NormalizeExt, ObligationCauseCode, ObligationCtxt, StructurallyNormalizeExt, +}; use std::collections::hash_map::Entry; use std::slice; @@ -63,9 +66,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lint::builtin::UNREACHABLE_CODE, id, span, - &msg, + msg.clone(), |lint| { - lint.span_label(span, &msg).span_label( + lint.span_label(span, msg).span_label( orig_span, custom_note .unwrap_or("any code following this expression is unreachable"), @@ -275,7 +278,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => { self.tcx.sess.delay_span_bug( expr.span, - &format!( + format!( "while adjusting {:?}, can't compose {:?} and {:?}", expr, entry.get(), @@ -420,9 +423,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ast_c: &hir::AnonConst, param_def_id: DefId, ) -> ty::Const<'tcx> { - let const_def = - ty::WithOptConstParam { did: ast_c.def_id, const_param_did: Some(param_def_id) }; - let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def); + let did = ast_c.def_id; + self.tcx.feed_anon_const_type(did, self.tcx.type_of(param_def_id)); + let c = ty::Const::from_anon_const(self.tcx, did); self.register_wf_obligation( c.into(), self.tcx.hir().span(ast_c.hir_id), @@ -827,7 +830,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } QPath::TypeRelative(ref qself, ref segment) => { // Don't use `self.to_ty`, since this will register a WF obligation. - // If we're trying to call a non-existent method on a trait + // If we're trying to call a nonexistent method on a trait // (e.g. `MyTrait::missing_method`), then resolution will // give us a `QPath::TypeRelative` with a trait object as // `qself`. In that case, we want to avoid registering a WF obligation @@ -853,23 +856,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let item_name = item_segment.ident; let result = self .resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id) + .and_then(|r| { + // lint bare trait if the method is found in the trait + if span.edition().rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { + diag.emit(); + } + Ok(r) + }) .or_else(|error| { + let guar = self + .tcx + .sess + .delay_span_bug(span, "method resolution should've emitted an error"); let result = match error { method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)), - _ => Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()), + _ => Err(guar), }; + let trait_missing_method = + matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait(); // If we have a path like `MyTrait::missing_method`, then don't register // a WF obligation for `dyn MyTrait` when method lookup fails. Otherwise, // register a WF obligation so that we can detect any additional // errors in the self type. - if !(matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait()) { + if !trait_missing_method { self.register_wf_obligation( ty.raw.into(), qself.span, traits::WellFormed(None), ); } + + // emit or cancel the diagnostic for bare traits + if span.edition().rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { + if trait_missing_method { + // cancel the diag for bare traits when meeting `MyTrait::missing_method` + diag.cancel(); + } else { + diag.emit(); + } + } + if item_name.name != kw::Empty { if let Some(mut e) = self.report_method_error( span, @@ -879,10 +906,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error, None, Expectation::NoExpectation, + trait_missing_method && span.edition().rust_2021(), // emits missing method for trait only after edition 2021 ) { e.emit(); } } + result }); @@ -989,8 +1018,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .typeck_results .borrow() .expr_ty_adjusted_opt(rcvr) - .and_then(|ty| expected.map(|expected_ty| expected_ty.peel_refs() == ty.peel_refs())) - .unwrap_or(false); + .zip(expected) + .is_some_and(|(ty, expected_ty)| expected_ty.peel_refs() == ty.peel_refs()); let prev_call_mutates_and_returns_unit = || { self.typeck_results @@ -998,14 +1027,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .type_dependent_def_id(expr.hir_id) .map(|def_id| self.tcx.fn_sig(def_id).skip_binder().skip_binder()) .and_then(|sig| sig.inputs_and_output.split_last()) - .map(|(output, inputs)| { + .is_some_and(|(output, inputs)| { output.is_unit() && inputs .get(0) .and_then(|self_ty| self_ty.ref_mutability()) - .map_or(false, rustc_ast::Mutability::is_mut) + .is_some_and(rustc_ast::Mutability::is_mut) }) - .unwrap_or(false) }; if !(rcvr_has_the_expected_type || prev_call_mutates_and_returns_unit()) { @@ -1034,15 +1062,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcvr.span, "you probably want to use this value after calling the method...", ); - err.span_note(sp, &modifies_rcvr_note); - err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident)); + err.span_note(sp, modifies_rcvr_note); + err.note(format!("...instead of the `()` output of method `{}`", path_segment.ident)); } else if let ExprKind::MethodCall(..) = rcvr.kind { err.span_note( sp, modifies_rcvr_note.clone() + ", it is not meant to be used in method chains.", ); } else { - err.span_note(sp, &modifies_rcvr_note); + err.span_note(sp, modifies_rcvr_note); } } @@ -1172,16 +1200,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let has_self = path_segs - .last() - .map(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self) - .unwrap_or(false); + let has_self = + path_segs.last().is_some_and(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self); let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res { let ty = self.handle_raw_ty(span, tcx.at(span).type_of(impl_def_id).subst_identity()); match ty.normalized.ty_adt_def() { Some(adt_def) if adt_def.has_ctor() => { let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap(); + // Check the visibility of the ctor. + let vis = tcx.visibility(ctor_def_id); + if !vis.is_accessible_from(tcx.parent_module(hir_id).to_def_id(), tcx) { + tcx.sess + .emit_err(CtorIsPrivate { span, def: tcx.def_path_str(adt_def.did()) }); + } let new_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id); let user_substs = Self::user_substs_for_adt(ty); user_self_ty = user_substs.user_self_ty; @@ -1374,7 +1406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(_) => { self.tcx.sess.delay_span_bug( span, - &format!( + format!( "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?", self_ty, impl_ty, @@ -1434,10 +1466,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Resolves `typ` by a single level if `typ` is a type variable. + /// + /// When the new solver is enabled, this will also attempt to normalize + /// the type if it's a projection (note that it will not deeply normalize + /// projections within the type, just the outermost layer of the type). + /// /// If no resolution is possible, then an error is reported. /// Numeric inference variables may be left unresolved. pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - let ty = self.resolve_vars_with_obligations(ty); + let mut ty = self.resolve_vars_with_obligations(ty); + + if self.tcx.trait_solver_next() + && let ty::Alias(ty::Projection, _) = ty.kind() + { + match self + .at(&self.misc(sp), self.param_env) + .structurally_normalize(ty, &mut **self.fulfillment_cx.borrow_mut()) + { + Ok(normalized_ty) => { + ty = normalized_ty; + }, + Err(errors) => { + let guar = self.err_ctxt().report_fulfillment_errors(&errors); + return self.tcx.ty_error(guar); + } + } + } + if !ty.is_ty_var() { ty } else { |