Auto merge of #100676 - lcnr:implied-bounds-yay, r=nikomatsakis

implied bounds: explicitly state which types are assumed to be wf

Adds a new query which maps each definition to the types which that definition assumes to be well formed. The intent is to make it easier to reason about implied bounds.

This change should not influence the user-facing behavior of rustc. Notably, `borrowck` still only assumes that the function signature of associated functions is well formed while `wfcheck` assumes that the both the function signature and the impl trait ref is well formed. Not sure if that by itself can trigger UB or whether it's just annoying.

As a next step, we can add `WellFormed` predicates to `predicates_of` of these items and can stop adding the wf bounds at each place which uses them. I also intend to move the computation from `assumed_wf_types` to `implied_bounds` into the `param_env` computation. This requires me to take a deeper look at `compare_predicate_entailment` which is currently somewhat weird wrt implied bounds so I am not touching this here.

r? `@nikomatsakis`
This commit is contained in:
bors 2022-08-22 06:10:26 +00:00
commit a9bb589cd6
24 changed files with 321 additions and 237 deletions

View File

@ -765,6 +765,14 @@ rustc_queries! {
desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) }
}
/// Returns the types assumed to be well formed while "inside" of the given item.
///
/// Note that we've liberated the late bound regions of function signatures, so
/// this can not be used to check whether these types are well formed.
query assumed_wf_types(key: DefId) -> &'tcx ty::List<Ty<'tcx>> {
desc { |tcx| "computing the implied bounds of {}", tcx.def_path_str(key) }
}
/// Computes the signature of the function.
query fn_sig(key: DefId) -> ty::PolyFnSig<'tcx> {
desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) }

View File

@ -65,6 +65,10 @@ impl<T> List<T> {
pub fn len(&self) -> usize {
self.len
}
pub fn as_slice(&self) -> &[T] {
self
}
}
impl<T: Copy> List<T> {

View File

@ -3,7 +3,8 @@ use std::cell::RefCell;
use super::TraitEngine;
use super::{ChalkFulfillmentContext, FulfillmentContext};
use crate::infer::InferCtxtExt;
use rustc_hir::def_id::DefId;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::infer::{InferCtxt, InferOk};
use rustc_infer::traits::{
FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _,
@ -12,6 +13,7 @@ use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span;
pub trait TraitEngineExt<'tcx> {
fn new(tcx: TyCtxt<'tcx>) -> Box<Self>;
@ -109,4 +111,23 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
pub fn select_all_or_error(&self) -> Vec<FulfillmentError<'tcx>> {
self.engine.borrow_mut().select_all_or_error(self.infcx)
}
pub fn assumed_wf_types(
&self,
param_env: ty::ParamEnv<'tcx>,
span: Span,
def_id: LocalDefId,
) -> FxHashSet<Ty<'tcx>> {
let tcx = self.infcx.tcx;
let assumed_wf_types = tcx.assumed_wf_types(def_id);
let mut implied_bounds = FxHashSet::default();
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let cause = ObligationCause::misc(span, hir_id);
for ty in assumed_wf_types {
implied_bounds.insert(ty);
let normalized = self.normalize(cause.clone(), param_env, ty);
implied_bounds.insert(normalized);
}
implied_bounds
}
}

View File

@ -0,0 +1,60 @@
use crate::rustc_middle::ty::DefIdTree;
use rustc_hir::{def::DefKind, def_id::DefId};
use rustc_middle::ty::{self, Ty, TyCtxt};
pub fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers { assumed_wf_types, ..*providers };
}
fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx ty::List<Ty<'tcx>> {
match tcx.def_kind(def_id) {
DefKind::Fn => {
let sig = tcx.fn_sig(def_id);
let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig);
liberated_sig.inputs_and_output
}
DefKind::AssocFn => {
let sig = tcx.fn_sig(def_id);
let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig);
let mut assumed_wf_types: Vec<_> =
tcx.assumed_wf_types(tcx.parent(def_id)).as_slice().into();
assumed_wf_types.extend(liberated_sig.inputs_and_output);
tcx.intern_type_list(&assumed_wf_types)
}
DefKind::Impl => match tcx.impl_trait_ref(def_id) {
Some(trait_ref) => {
let types: Vec<_> = trait_ref.substs.types().collect();
tcx.intern_type_list(&types)
}
// Only the impl self type
None => tcx.intern_type_list(&[tcx.type_of(def_id)]),
},
DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
DefKind::Mod
| DefKind::Struct
| DefKind::Union
| DefKind::Enum
| DefKind::Variant
| DefKind::Trait
| DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::TraitAlias
| DefKind::TyParam
| DefKind::Const
| DefKind::ConstParam
| DefKind::Static(_)
| DefKind::Ctor(_, _)
| DefKind::Macro(_)
| DefKind::ExternCrate
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
| DefKind::InlineConst
| DefKind::OpaqueTy
| DefKind::Field
| DefKind::LifetimeParam
| DefKind::GlobalAsm
| DefKind::Closure
| DefKind::Generator => ty::List::empty(),
}
}

View File

@ -21,6 +21,7 @@ use rustc_middle::ty::query::Providers;
mod assoc;
mod common_traits;
mod consts;
mod implied_bounds;
pub mod instance;
mod needs_drop;
pub mod representability;
@ -30,6 +31,7 @@ pub fn provide(providers: &mut Providers) {
assoc::provide(providers);
common_traits::provide(providers);
consts::provide(providers);
implied_bounds::provide(providers);
needs_drop::provide(providers);
ty::provide(providers);
instance::provide(providers);

View File

@ -1,6 +1,5 @@
use super::potentially_plural_count;
use crate::check::regionck::OutlivesEnvironmentExt;
use crate::check::wfcheck;
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
@ -71,6 +70,72 @@ pub(crate) fn compare_impl_method<'tcx>(
}
}
/// This function is best explained by example. Consider a trait:
///
/// trait Trait<'t, T> {
/// // `trait_m`
/// fn method<'a, M>(t: &'t T, m: &'a M) -> Self;
/// }
///
/// And an impl:
///
/// impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
/// // `impl_m`
/// fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo;
/// }
///
/// We wish to decide if those two method types are compatible.
/// For this we have to show that, assuming the bounds of the impl hold, the
/// bounds of `trait_m` imply the bounds of `impl_m`.
///
/// We start out with `trait_to_impl_substs`, that maps the trait
/// type parameters to impl type parameters. This is taken from the
/// impl trait reference:
///
/// trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo}
///
/// We create a mapping `dummy_substs` that maps from the impl type
/// parameters to fresh types and regions. For type parameters,
/// this is the identity transform, but we could as well use any
/// placeholder types. For regions, we convert from bound to free
/// regions (Note: but only early-bound regions, i.e., those
/// declared on the impl or used in type parameter bounds).
///
/// impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 }
///
/// Now we can apply `placeholder_substs` to the type of the impl method
/// to yield a new function type in terms of our fresh, placeholder
/// types:
///
/// <'b> fn(t: &'i0 U0, m: &'b) -> Foo
///
/// We now want to extract and substitute the type of the *trait*
/// method and compare it. To do so, we must create a compound
/// substitution by combining `trait_to_impl_substs` and
/// `impl_to_placeholder_substs`, and also adding a mapping for the method
/// type parameters. We extend the mapping to also include
/// the method parameters.
///
/// trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 }
///
/// Applying this to the trait method type yields:
///
/// <'a> fn(t: &'i0 U0, m: &'a) -> Foo
///
/// This type is also the same but the name of the bound region (`'a`
/// vs `'b`). However, the normal subtyping rules on fn types handle
/// this kind of equivalency just fine.
///
/// We now use these substitutions to ensure that all declared bounds are
/// satisfied by the implementation's method.
///
/// We do this by creating a parameter environment which contains a
/// substitution corresponding to `impl_to_placeholder_substs`. We then build
/// `trait_to_placeholder_substs` and use it to convert the predicates contained
/// in the `trait_m` generics to the placeholder form.
///
/// Finally we register each of these predicates as an obligation and check that
/// they hold.
fn compare_predicate_entailment<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m: &ty::AssocItem,
@ -97,69 +162,6 @@ fn compare_predicate_entailment<'tcx>(
},
);
// This code is best explained by example. Consider a trait:
//
// trait Trait<'t, T> {
// fn method<'a, M>(t: &'t T, m: &'a M) -> Self;
// }
//
// And an impl:
//
// impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
// fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo;
// }
//
// We wish to decide if those two method types are compatible.
//
// We start out with trait_to_impl_substs, that maps the trait
// type parameters to impl type parameters. This is taken from the
// impl trait reference:
//
// trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo}
//
// We create a mapping `dummy_substs` that maps from the impl type
// parameters to fresh types and regions. For type parameters,
// this is the identity transform, but we could as well use any
// placeholder types. For regions, we convert from bound to free
// regions (Note: but only early-bound regions, i.e., those
// declared on the impl or used in type parameter bounds).
//
// impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 }
//
// Now we can apply placeholder_substs to the type of the impl method
// to yield a new function type in terms of our fresh, placeholder
// types:
//
// <'b> fn(t: &'i0 U0, m: &'b) -> Foo
//
// We now want to extract and substitute the type of the *trait*
// method and compare it. To do so, we must create a compound
// substitution by combining trait_to_impl_substs and
// impl_to_placeholder_substs, and also adding a mapping for the method
// type parameters. We extend the mapping to also include
// the method parameters.
//
// trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 }
//
// Applying this to the trait method type yields:
//
// <'a> fn(t: &'i0 U0, m: &'a) -> Foo
//
// This type is also the same but the name of the bound region ('a
// vs 'b). However, the normal subtyping rules on fn types handle
// this kind of equivalency just fine.
//
// We now use these substitutions to ensure that all declared bounds are
// satisfied by the implementation's method.
//
// We do this by creating a parameter environment which contains a
// substitution corresponding to impl_to_placeholder_substs. We then build
// trait_to_placeholder_substs and use it to convert the predicates contained
// in the trait_m.generics to the placeholder form.
//
// Finally we register each of these predicates as an obligation in
// a fresh FulfillmentCtxt, and invoke select_all_or_error.
// Create mapping from impl to placeholder.
let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
@ -1445,14 +1447,17 @@ pub fn check_type_bounds<'tcx>(
};
debug!(?normalize_param_env);
let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
tcx.infer_ctxt().enter(move |infcx| {
let ocx = ObligationCtxt::new(&infcx);
let assumed_wf_types =
ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty.def_id.expect_local());
let mut selcx = traits::SelectionContext::new(&infcx);
let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
let normalize_cause = ObligationCause::new(
impl_ty_span,
impl_ty_hir_id,
@ -1508,17 +1513,8 @@ pub fn check_type_bounds<'tcx>(
// Finally, resolve all regions. This catches wily misuses of
// lifetime parameters.
let implied_bounds = match impl_ty.container {
ty::TraitContainer => FxHashSet::default(),
ty::ImplContainer => wfcheck::impl_implied_bounds(
tcx,
param_env,
container_id.expect_local(),
impl_ty_span,
),
};
let mut outlives_environment = OutlivesEnvironment::new(param_env);
outlives_environment.add_implied_bounds(&infcx, implied_bounds, impl_ty_hir_id);
outlives_environment.add_implied_bounds(&infcx, assumed_wf_types, impl_ty_hir_id);
infcx.check_region_obligations_and_report_errors(
impl_ty.def_id.expect_local(),
&outlives_environment,

View File

@ -10,7 +10,6 @@ use rustc_hir::ItemKind;
use rustc_infer::infer::outlives::env::{OutlivesEnvironment, RegionBoundPairs};
use rustc_infer::infer::outlives::obligations::TypeOutlives;
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::Normalized;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
use rustc_middle::ty::trait_def::TraitSpecializationKind;
@ -24,8 +23,6 @@ use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::autoderef::Autoderef;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::query::normalize::AtExt;
use rustc_trait_selection::traits::query::NoSolution;
use rustc_trait_selection::traits::{
self, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc,
};
@ -86,18 +83,21 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
body_def_id: LocalDefId,
f: F,
) where
F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>) -> FxHashSet<Ty<'tcx>>,
F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>),
{
let param_env = tcx.param_env(body_def_id);
let body_id = tcx.hir().local_def_id_to_hir_id(body_def_id);
tcx.infer_ctxt().enter(|ref infcx| {
let ocx = ObligationCtxt::new(infcx);
let assumed_wf_types = ocx.assumed_wf_types(param_env, span, body_def_id);
let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env };
if !tcx.features().trivial_bounds {
wfcx.check_false_global_bounds()
}
let wf_tys = f(&mut wfcx);
f(&mut wfcx);
let errors = wfcx.select_all_or_error();
if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
@ -105,7 +105,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
}
let mut outlives_environment = OutlivesEnvironment::new(param_env);
outlives_environment.add_implied_bounds(infcx, wf_tys, body_id);
outlives_environment.add_implied_bounds(infcx, assumed_wf_types, body_id);
infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
})
}
@ -976,15 +976,9 @@ fn check_associated_item(
enter_wf_checking_ctxt(tcx, span, item_id, |wfcx| {
let item = tcx.associated_item(item_id);
let (mut implied_bounds, self_ty) = match item.container {
ty::TraitContainer => (FxHashSet::default(), tcx.types.self_param),
ty::ImplContainer => {
let def_id = item.container_id(tcx);
(
impl_implied_bounds(tcx, wfcx.param_env, def_id.expect_local(), span),
tcx.type_of(def_id),
)
}
let self_ty = match item.container {
ty::TraitContainer => tcx.types.self_param,
ty::ImplContainer => tcx.type_of(item.container_id(tcx)),
};
match item.kind {
@ -1002,7 +996,6 @@ fn check_associated_item(
sig,
hir_sig.decl,
item.def_id.expect_local(),
&mut implied_bounds,
);
check_method_receiver(wfcx, hir_sig, item, self_ty);
}
@ -1017,8 +1010,6 @@ fn check_associated_item(
}
}
}
implied_bounds
})
}
@ -1118,9 +1109,6 @@ fn check_type_defn<'tcx, F>(
}
check_where_clauses(wfcx, item.span, item.def_id);
// No implied bounds in a struct definition.
FxHashSet::default()
});
}
@ -1144,9 +1132,7 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
}
enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| {
check_where_clauses(wfcx, item.span, item.def_id);
FxHashSet::default()
check_where_clauses(wfcx, item.span, item.def_id)
});
// Only check traits, don't check trait aliases
@ -1186,9 +1172,7 @@ fn check_item_fn(
) {
enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| {
let sig = tcx.fn_sig(def_id);
let mut implied_bounds = FxHashSet::default();
check_fn_or_method(wfcx, ident.span, sig, decl, def_id, &mut implied_bounds);
implied_bounds
check_fn_or_method(wfcx, ident.span, sig, decl, def_id);
})
}
@ -1231,9 +1215,6 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_fo
tcx.require_lang_item(LangItem::Sync, Some(ty_span)),
);
}
// No implied bounds in a const, etc.
FxHashSet::default()
});
}
@ -1284,8 +1265,6 @@ fn check_impl<'tcx>(
}
check_where_clauses(wfcx, item.span, item.def_id);
impl_implied_bounds(tcx, wfcx.param_env, item.def_id, item.span)
});
}
@ -1479,7 +1458,6 @@ fn check_fn_or_method<'tcx>(
sig: ty::PolyFnSig<'tcx>,
hir_decl: &hir::FnDecl<'_>,
def_id: LocalDefId,
implied_bounds: &mut FxHashSet<Ty<'tcx>>,
) {
let tcx = wfcx.tcx();
let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);
@ -1521,15 +1499,8 @@ fn check_fn_or_method<'tcx>(
);
}
implied_bounds.extend(sig.inputs());
wfcx.register_wf_obligation(hir_decl.output.span(), None, sig.output().into());
// FIXME(#27579) return types should not be implied bounds
implied_bounds.insert(sig.output());
debug!(?implied_bounds);
check_where_clauses(wfcx, span, def_id);
}
@ -1924,40 +1895,6 @@ impl<'a, 'tcx> WfCheckingCtxt<'a, 'tcx> {
}
}
pub fn impl_implied_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
impl_def_id: LocalDefId,
span: Span,
) -> FxHashSet<Ty<'tcx>> {
// We completely ignore any obligations caused by normalizing the types
// we assume to be well formed. Considering that the user of the implied
// bounds will also normalize them, we leave it to them to emit errors
// which should result in better causes and spans.
tcx.infer_ctxt().enter(|infcx| {
let cause = ObligationCause::misc(span, tcx.hir().local_def_id_to_hir_id(impl_def_id));
match tcx.impl_trait_ref(impl_def_id) {
Some(trait_ref) => {
// Trait impl: take implied bounds from all types that
// appear in the trait reference.
match infcx.at(&cause, param_env).normalize(trait_ref) {
Ok(Normalized { value, obligations: _ }) => value.substs.types().collect(),
Err(NoSolution) => FxHashSet::default(),
}
}
None => {
// Inherent impl: take implied bounds from the `self` type.
let self_ty = tcx.type_of(impl_def_id);
match infcx.at(&cause, param_env).normalize(self_ty) {
Ok(Normalized { value, obligations: _ }) => FxHashSet::from_iter([value]),
Err(NoSolution) => FxHashSet::default(),
}
}
}
})
}
fn error_392(
tcx: TyCtxt<'_>,
span: Span,

View File

@ -66,26 +66,24 @@
//! on traits with methods can.
use crate::check::regionck::OutlivesEnvironmentExt;
use crate::check::wfcheck::impl_implied_bounds;
use crate::constrained_generic_params as cgp;
use crate::errors::SubstsOnOverriddenImpl;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::specialization_graph::Node;
use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
use rustc_span::Span;
use rustc_trait_selection::traits::{self, translate_substs, wf};
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt};
pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
if let Some(node) = parent_specialization_node(tcx, impl_def_id) {
tcx.infer_ctxt().enter(|infcx| {
check_always_applicable(&infcx, impl_def_id, node);
});
check_always_applicable(tcx, impl_def_id, node);
}
}
@ -105,16 +103,14 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Opti
}
/// Check that `impl1` is a sound specialization
fn check_always_applicable(infcx: &InferCtxt<'_, '_>, impl1_def_id: LocalDefId, impl2_node: Node) {
if let Some((impl1_substs, impl2_substs)) = get_impl_substs(infcx, impl1_def_id, impl2_node) {
fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node) {
if let Some((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) {
let impl2_def_id = impl2_node.def_id();
debug!(
"check_always_applicable(\nimpl1_def_id={:?},\nimpl2_def_id={:?},\nimpl2_substs={:?}\n)",
impl1_def_id, impl2_def_id, impl2_substs
);
let tcx = infcx.tcx;
let parent_substs = if impl2_node.is_from_trait() {
impl2_substs.to_vec()
} else {
@ -124,7 +120,7 @@ fn check_always_applicable(infcx: &InferCtxt<'_, '_>, impl1_def_id: LocalDefId,
let span = tcx.def_span(impl1_def_id);
check_static_lifetimes(tcx, &parent_substs, span);
check_duplicate_params(tcx, impl1_substs, &parent_substs, span);
check_predicates(infcx, impl1_def_id, impl1_substs, impl2_node, impl2_substs, span);
check_predicates(tcx, impl1_def_id, impl1_substs, impl2_node, impl2_substs, span);
}
}
@ -139,32 +135,38 @@ fn check_always_applicable(infcx: &InferCtxt<'_, '_>, impl1_def_id: LocalDefId,
///
/// Would return `S1 = [C]` and `S2 = [Vec<C>, C]`.
fn get_impl_substs<'tcx>(
infcx: &InferCtxt<'_, 'tcx>,
tcx: TyCtxt<'tcx>,
impl1_def_id: LocalDefId,
impl2_node: Node,
) -> Option<(SubstsRef<'tcx>, SubstsRef<'tcx>)> {
let tcx = infcx.tcx;
let param_env = tcx.param_env(impl1_def_id);
tcx.infer_ctxt().enter(|ref infcx| {
let ocx = ObligationCtxt::new(infcx);
let param_env = tcx.param_env(impl1_def_id);
let impl1_hir_id = tcx.hir().local_def_id_to_hir_id(impl1_def_id);
let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id());
let impl2_substs =
translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node);
let assumed_wf_types =
ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id);
let mut outlives_env = OutlivesEnvironment::new(param_env);
let implied_bounds =
impl_implied_bounds(infcx.tcx, param_env, impl1_def_id, tcx.def_span(impl1_def_id));
outlives_env.add_implied_bounds(
infcx,
implied_bounds,
tcx.hir().local_def_id_to_hir_id(impl1_def_id),
);
infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
let span = tcx.def_span(impl1_def_id);
tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
return None;
};
Some((impl1_substs, impl2_substs))
let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id());
let impl2_substs =
translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
ocx.infcx.report_fulfillment_errors(&errors, None, false);
return None;
}
let mut outlives_env = OutlivesEnvironment::new(param_env);
outlives_env.add_implied_bounds(infcx, assumed_wf_types, impl1_hir_id);
infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
let span = tcx.def_span(impl1_def_id);
tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
return None;
};
Some((impl1_substs, impl2_substs))
})
}
/// Returns a list of all of the unconstrained subst of the given impl.
@ -279,14 +281,13 @@ fn check_static_lifetimes<'tcx>(
/// * a well-formed predicate of a type argument of the trait being implemented,
/// including the `Self`-type.
fn check_predicates<'tcx>(
infcx: &InferCtxt<'_, 'tcx>,
tcx: TyCtxt<'tcx>,
impl1_def_id: LocalDefId,
impl1_substs: SubstsRef<'tcx>,
impl2_node: Node,
impl2_substs: SubstsRef<'tcx>,
span: Span,
) {
let tcx = infcx.tcx;
let instantiated = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs);
let impl1_predicates: Vec<_> = traits::elaborate_predicates_with_span(
tcx,
@ -343,19 +344,23 @@ fn check_predicates<'tcx>(
// Include the well-formed predicates of the type parameters of the impl.
for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs {
if let Some(obligations) = wf::obligations(
infcx,
tcx.param_env(impl1_def_id),
tcx.hir().local_def_id_to_hir_id(impl1_def_id),
0,
arg,
span,
) {
tcx.infer_ctxt().enter(|ref infcx| {
let obligations = wf::obligations(
infcx,
tcx.param_env(impl1_def_id),
tcx.hir().local_def_id_to_hir_id(impl1_def_id),
0,
arg,
span,
)
.unwrap();
assert!(!obligations.needs_infer());
impl2_predicates.extend(
traits::elaborate_obligations(tcx, obligations)
.map(|obligation| obligation.predicate),
)
}
})
}
impl2_predicates.extend(
traits::elaborate_predicates_with_span(tcx, always_applicable_traits)

View File

@ -1,8 +1,8 @@
error[E0277]: the trait bound `Self: Get` is not satisfied
--> $DIR/associated-types-for-unimpl-trait.rs:10:40
--> $DIR/associated-types-for-unimpl-trait.rs:10:5
|
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
| ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
help: consider further restricting `Self`
|

View File

@ -1,8 +1,8 @@
error[E0277]: the trait bound `T: Get` is not satisfied
--> $DIR/associated-types-no-suitable-bound.rs:11:21
--> $DIR/associated-types-no-suitable-bound.rs:11:5
|
LL | fn uhoh<T>(foo: <T as Get>::Value) {}
| ^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T`
|
help: consider restricting type parameter `T`
|

View File

@ -1,8 +1,8 @@
error[E0277]: the trait bound `Self: Get` is not satisfied
--> $DIR/associated-types-no-suitable-supertrait-2.rs:17:40
--> $DIR/associated-types-no-suitable-supertrait-2.rs:17:5
|
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
| ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
help: consider further restricting `Self`
|

View File

@ -1,14 +1,14 @@
error[E0277]: the trait bound `(T, U): Get` is not satisfied
--> $DIR/associated-types-no-suitable-supertrait.rs:22:40
--> $DIR/associated-types-no-suitable-supertrait.rs:22:5
|
LL | fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {}
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)`
error[E0277]: the trait bound `Self: Get` is not satisfied
--> $DIR/associated-types-no-suitable-supertrait.rs:17:40
--> $DIR/associated-types-no-suitable-supertrait.rs:17:5
|
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
| ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
help: consider further restricting `Self`
|

View File

@ -1,8 +1,8 @@
error[E0277]: the trait bound `Self: Get` is not satisfied
--> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:40
--> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:5
|
LL | fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value);
| ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
help: consider further restricting `Self`
|

View File

@ -45,16 +45,20 @@ LL | pub trait ThriftService<Bug: NotFoo + Foo>:
| +++++
error[E0277]: the trait bound `(): Foo` is not satisfied
--> $DIR/issue-59324.rs:23:29
--> $DIR/issue-59324.rs:23:1
|
LL | fn with_factory<H>(factory: dyn ThriftService<()>) {}
| ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
error[E0277]: the trait bound `Bug: Foo` is not satisfied
--> $DIR/issue-59324.rs:16:8
--> $DIR/issue-59324.rs:16:5
|
LL | fn get_service(
| ^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
LL | / fn get_service(
LL | |
LL | |
LL | | &self,
LL | | ) -> Self::AssocType;
| |_________________________^ the trait `Foo` is not implemented for `Bug`
|
help: consider further restricting this bound
|

View File

@ -1,8 +1,10 @@
error[E0277]: the trait bound `isize: HasState` is not satisfied
--> $DIR/issue-18611.rs:1:18
--> $DIR/issue-18611.rs:1:1
|
LL | fn add_state(op: <isize as HasState>::State) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasState` is not implemented for `isize`
LL | / fn add_state(op: <isize as HasState>::State) {
LL | |
LL | | }
| |_^ the trait `HasState` is not implemented for `isize`
error: aborting due to previous error

View File

@ -1,8 +1,14 @@
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> $DIR/issue-20831-debruijn.rs:28:8
--> $DIR/issue-20831-debruijn.rs:28:5
|
LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
| ^^^^^^^^^
LL | / fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
LL | | // Not obvious, but there is an implicit lifetime here -------^
LL | |
LL | | //
... |
LL | | self.sub = t;
LL | | }
| |_____^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> $DIR/issue-20831-debruijn.rs:28:58
@ -15,10 +21,16 @@ note: ...but the lifetime must also be valid for the lifetime `'a` as defined he
LL | impl<'a> Publisher<'a> for MyStruct<'a> {
| ^^
note: ...so that the types are compatible
--> $DIR/issue-20831-debruijn.rs:28:8
--> $DIR/issue-20831-debruijn.rs:28:5
|
LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
| ^^^^^^^^^
LL | / fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
LL | | // Not obvious, but there is an implicit lifetime here -------^
LL | |
LL | | //
... |
LL | | self.sub = t;
LL | | }
| |_____^
= note: expected `<MyStruct<'a> as Publisher<'_>>`
found `<MyStruct<'_> as Publisher<'_>>`

View File

@ -6,7 +6,8 @@ trait Trait2<'a> {
}
fn _ice(param: Box<dyn for <'a> Trait1<<() as Trait2<'a>>::Ty>>) {
//~^ the trait bound `for<'a> (): Trait2<'a>` is not satisfied
//~^ ERROR the trait bound `for<'a> (): Trait2<'a>` is not satisfied
//~| ERROR the trait bound `for<'a> (): Trait2<'a>` is not satisfied
let _e: (usize, usize) = unsafe{mem::transmute(param)};
}

View File

@ -1,9 +1,19 @@
error[E0277]: the trait bound `for<'a> (): Trait2<'a>` is not satisfied
--> $DIR/issue-35570.rs:8:1
|
LL | / fn _ice(param: Box<dyn for <'a> Trait1<<() as Trait2<'a>>::Ty>>) {
LL | |
LL | |
LL | | let _e: (usize, usize) = unsafe{mem::transmute(param)};
LL | | }
| |_^ the trait `for<'a> Trait2<'a>` is not implemented for `()`
error[E0277]: the trait bound `for<'a> (): Trait2<'a>` is not satisfied
--> $DIR/issue-35570.rs:8:40
|
LL | fn _ice(param: Box<dyn for <'a> Trait1<<() as Trait2<'a>>::Ty>>) {
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait2<'a>` is not implemented for `()`
error: aborting due to previous error
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -1,8 +1,8 @@
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'d` due to conflicting requirements
--> $DIR/normalization-bounds-error.rs:12:4
--> $DIR/normalization-bounds-error.rs:12:1
|
LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
| ^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'d` as defined here...
--> $DIR/normalization-bounds-error.rs:12:14
@ -15,10 +15,10 @@ note: ...but the lifetime must also be valid for the lifetime `'a` as defined he
LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
| ^^
note: ...so that the types are compatible
--> $DIR/normalization-bounds-error.rs:12:4
--> $DIR/normalization-bounds-error.rs:12:1
|
LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
| ^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `Visitor<'d>`
found `Visitor<'_>`

View File

@ -19,7 +19,8 @@ trait Trait2<'a, 'b> {
// since for it to be WF, we would need to know that `'y: 'x`, but we
// do not infer that.
fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
//~^ the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied
//~^ ERROR the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied
//~| ERROR the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied
{
}

View File

@ -1,3 +1,18 @@
error[E0277]: the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied
--> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:1
|
LL | / fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
LL | |
LL | |
LL | | {
LL | | }
| |_^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T`
|
help: consider restricting type parameter `T`
|
LL | fn callee<'x, 'y, T: for<'z> Trait2<'y, 'z>>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
| ++++++++++++++++++++++++
error[E0277]: the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied
--> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:49
|
@ -9,6 +24,6 @@ help: consider restricting type parameter `T`
LL | fn callee<'x, 'y, T: for<'z> Trait2<'y, 'z>>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
| ++++++++++++++++++++++++
error: aborting due to previous error
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -1,8 +1,12 @@
error[E0277]: the trait bound `B: Clone` is not satisfied
--> $DIR/issue-79224.rs:18:17
--> $DIR/issue-79224.rs:18:1
|
LL | impl<B: ?Sized> Display for Cow<'_, B> {
| ^^^^^^^ the trait `Clone` is not implemented for `B`
LL | / impl<B: ?Sized> Display for Cow<'_, B> {
LL | | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
LL | | write!(f, "foo")
LL | | }
LL | | }
| |_^ the trait `Clone` is not implemented for `B`
|
= note: required for `B` to implement `ToOwned`
help: consider further restricting this bound
@ -11,10 +15,12 @@ LL | impl<B: ?Sized + std::clone::Clone> Display for Cow<'_, B> {
| +++++++++++++++++++
error[E0277]: the trait bound `B: Clone` is not satisfied
--> $DIR/issue-79224.rs:19:12
--> $DIR/issue-79224.rs:19:5
|
LL | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
| ^^^^^ the trait `Clone` is not implemented for `B`
LL | / fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
LL | | write!(f, "foo")
LL | | }
| |_____^ the trait `Clone` is not implemented for `B`
|
= note: required for `B` to implement `ToOwned`
help: consider further restricting this bound

View File

@ -1,8 +1,8 @@
error[E0277]: the trait bound `Foo: HasComponent<()>` is not satisfied
--> $DIR/issue-91594.rs:10:6
--> $DIR/issue-91594.rs:10:1
|
LL | impl HasComponent<<Foo as Component<Foo>>::Interface> for Foo {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo`
|
= help: the trait `HasComponent<<Foo as Component<Foo>>::Interface>` is implemented for `Foo`
note: required for `Foo` to implement `Component<Foo>`

View File

@ -1,8 +1,8 @@
error[E0277]: the trait bound `(): Foo` is not satisfied
--> $DIR/wf-foreign-fn-decl-ret.rs:11:25
--> $DIR/wf-foreign-fn-decl-ret.rs:11:5
|
LL | pub fn lint_me() -> <() as Foo>::Assoc;
| ^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
error[E0277]: the trait bound `u32: Unsatisfied` is not satisfied
--> $DIR/wf-foreign-fn-decl-ret.rs:14:32