summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs')
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs105
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 {