Elaborate predicates in min_specialization checks
Supertraits of specialization markers could circumvent checks for min_specialization. Elaborating predicates prevents this.
This commit is contained in:
parent
6dc08b909b
commit
c8f86cad2d
4 changed files with 76 additions and 18 deletions
|
@ -64,7 +64,9 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
|
||||||
pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
|
pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
|
||||||
pub use self::structural_match::search_for_structural_match_violation;
|
pub use self::structural_match::search_for_structural_match_violation;
|
||||||
pub use self::structural_match::NonStructuralMatchTy;
|
pub use self::structural_match::NonStructuralMatchTy;
|
||||||
pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
|
pub use self::util::{
|
||||||
|
elaborate_obligations, elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs,
|
||||||
|
};
|
||||||
pub use self::util::{expand_trait_aliases, TraitAliasExpander};
|
pub use self::util::{expand_trait_aliases, TraitAliasExpander};
|
||||||
pub use self::util::{
|
pub use self::util::{
|
||||||
get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices,
|
get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices,
|
||||||
|
|
|
@ -74,7 +74,7 @@ use rustc_infer::infer::{InferCtxt, RegionckMode, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::specialization_graph::Node;
|
use rustc_infer::traits::specialization_graph::Node;
|
||||||
use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
|
use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
|
||||||
use rustc_middle::ty::trait_def::TraitSpecializationKind;
|
use rustc_middle::ty::trait_def::TraitSpecializationKind;
|
||||||
use rustc_middle::ty::{self, InstantiatedPredicates, TyCtxt, TypeFoldable};
|
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::traits::{self, translate_substs, wf};
|
use rustc_trait_selection::traits::{self, translate_substs, wf};
|
||||||
|
|
||||||
|
@ -294,13 +294,27 @@ fn check_predicates<'tcx>(
|
||||||
span: Span,
|
span: Span,
|
||||||
) {
|
) {
|
||||||
let tcx = infcx.tcx;
|
let tcx = infcx.tcx;
|
||||||
let impl1_predicates = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs);
|
let impl1_predicates: Vec<_> = traits::elaborate_predicates(
|
||||||
|
tcx,
|
||||||
|
tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs).predicates.into_iter(),
|
||||||
|
)
|
||||||
|
.map(|obligation| obligation.predicate)
|
||||||
|
.collect();
|
||||||
|
|
||||||
let mut impl2_predicates = if impl2_node.is_from_trait() {
|
let mut impl2_predicates = if impl2_node.is_from_trait() {
|
||||||
// Always applicable traits have to be always applicable without any
|
// Always applicable traits have to be always applicable without any
|
||||||
// assumptions.
|
// assumptions.
|
||||||
InstantiatedPredicates::empty()
|
Vec::new()
|
||||||
} else {
|
} else {
|
||||||
tcx.predicates_of(impl2_node.def_id()).instantiate(tcx, impl2_substs)
|
traits::elaborate_predicates(
|
||||||
|
tcx,
|
||||||
|
tcx.predicates_of(impl2_node.def_id())
|
||||||
|
.instantiate(tcx, impl2_substs)
|
||||||
|
.predicates
|
||||||
|
.into_iter(),
|
||||||
|
)
|
||||||
|
.map(|obligation| obligation.predicate)
|
||||||
|
.collect()
|
||||||
};
|
};
|
||||||
debug!(
|
debug!(
|
||||||
"check_always_applicable(\nimpl1_predicates={:?},\nimpl2_predicates={:?}\n)",
|
"check_always_applicable(\nimpl1_predicates={:?},\nimpl2_predicates={:?}\n)",
|
||||||
|
@ -322,13 +336,12 @@ fn check_predicates<'tcx>(
|
||||||
// which is sound because we forbid impls like the following
|
// which is sound because we forbid impls like the following
|
||||||
//
|
//
|
||||||
// impl<D: Debug> AlwaysApplicable for D { }
|
// impl<D: Debug> AlwaysApplicable for D { }
|
||||||
let always_applicable_traits =
|
let always_applicable_traits = impl1_predicates.iter().copied().filter(|&predicate| {
|
||||||
impl1_predicates.predicates.iter().copied().filter(|&predicate| {
|
matches!(
|
||||||
matches!(
|
trait_predicate_kind(tcx, predicate),
|
||||||
trait_predicate_kind(tcx, predicate),
|
Some(TraitSpecializationKind::AlwaysApplicable)
|
||||||
Some(TraitSpecializationKind::AlwaysApplicable)
|
)
|
||||||
)
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Include the well-formed predicates of the type parameters of the impl.
|
// Include the well-formed predicates of the type parameters of the impl.
|
||||||
for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs {
|
for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs {
|
||||||
|
@ -340,18 +353,19 @@ fn check_predicates<'tcx>(
|
||||||
arg,
|
arg,
|
||||||
span,
|
span,
|
||||||
) {
|
) {
|
||||||
impl2_predicates
|
impl2_predicates.extend(
|
||||||
.predicates
|
traits::elaborate_obligations(tcx, obligations)
|
||||||
.extend(obligations.into_iter().map(|obligation| obligation.predicate))
|
.map(|obligation| obligation.predicate),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl2_predicates.predicates.extend(
|
impl2_predicates.extend(
|
||||||
traits::elaborate_predicates(tcx, always_applicable_traits)
|
traits::elaborate_predicates(tcx, always_applicable_traits)
|
||||||
.map(|obligation| obligation.predicate),
|
.map(|obligation| obligation.predicate),
|
||||||
);
|
);
|
||||||
|
|
||||||
for predicate in impl1_predicates.predicates {
|
for predicate in impl1_predicates {
|
||||||
if !impl2_predicates.predicates.contains(&predicate) {
|
if !impl2_predicates.contains(&predicate) {
|
||||||
check_specialization_on(tcx, predicate, span)
|
check_specialization_on(tcx, predicate, span)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Check that supertraits cannot be used to work around min_specialization
|
||||||
|
// limitations.
|
||||||
|
|
||||||
|
#![feature(min_specialization)]
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
|
trait HasMethod {
|
||||||
|
fn method(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustc_unsafe_specialization_marker]
|
||||||
|
trait Marker: HasMethod {}
|
||||||
|
|
||||||
|
trait Spec {
|
||||||
|
fn spec_me(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Spec for T {
|
||||||
|
default fn spec_me(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Marker> Spec for T {
|
||||||
|
//~^ ERROR cannot specialize on trait `HasMethod`
|
||||||
|
fn spec_me(&self) {
|
||||||
|
self.method();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,13 @@
|
||||||
|
error: cannot specialize on trait `HasMethod`
|
||||||
|
--> $DIR/spec-marker-supertraits.rs:22:1
|
||||||
|
|
|
||||||
|
LL | / impl<T: Marker> Spec for T {
|
||||||
|
LL | |
|
||||||
|
LL | | fn spec_me(&self) {
|
||||||
|
LL | | self.method();
|
||||||
|
LL | | }
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue