rustc: don't reveal specializable polymorphic projections.

This commit is contained in:
Eduard Burtescu 2016-07-01 19:32:53 +03:00
parent ab26dbb96f
commit c976e073fd
2 changed files with 49 additions and 36 deletions

View File

@ -93,7 +93,7 @@ pub enum Reveal {
/// }
NotSpecializable,
/// At trans time, all projections will succeed.
/// At trans time, all monomorphic projections will succeed.
All,
}
@ -878,7 +878,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
candidate_set.vec.push(ProjectionTyCandidate::Select);
}
super::VtableImpl(ref impl_data) if selcx.projection_mode() != Reveal::All => {
super::VtableImpl(ref impl_data) => {
// We have to be careful when projecting out of an
// impl because of specialization. If we are not in
// trans (i.e., projection mode is not "any"), and the
@ -902,37 +902,43 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
impl_data.impl_def_id,
obligation.predicate.item_name);
let new_candidate = if let Some(node_item) = opt_node_item {
if node_item.node.is_from_trait() {
if node_item.item.ty.is_some() {
// The impl inherited a `type Foo =
// Bar` given in the trait, which is
// implicitly default. No candidate.
None
} else {
// The impl did not specify `type` and neither
// did the trait:
//
// ```rust
// trait Foo { type T; }
// impl Foo for Bar { }
// ```
//
// This is an error, but it will be
// reported in `check_impl_items_against_trait`.
// We accept it here but will flag it as
// an error when we confirm the candidate
// (which will ultimately lead to `normalize_to_error`
// being invoked).
Some(ProjectionTyCandidate::Select)
}
} else if node_item.item.defaultness.is_default() {
// The impl specified `default type Foo =
// Bar`. No candidate.
None
let is_default = if node_item.node.is_from_trait() {
// If true, the impl inherited a `type Foo = Bar`
// given in the trait, which is implicitly default.
// Otherwise, the impl did not specify `type` and
// neither did the trait:
//
// ```rust
// trait Foo { type T; }
// impl Foo for Bar { }
// ```
//
// This is an error, but it will be
// reported in `check_impl_items_against_trait`.
// We accept it here but will flag it as
// an error when we confirm the candidate
// (which will ultimately lead to `normalize_to_error`
// being invoked).
node_item.item.ty.is_some()
} else {
// The impl specified `type Foo = Bar`
// with no default. Add a candidate.
node_item.item.defaultness.is_default()
};
// Only reveal a specializable default if we're past type-checking
// and the obligations is monomorphic, otherwise passes such as
// transmute checking and polymorphic MIR optimizations could
// get a result which isn't correct for all monomorphizations.
if !is_default {
Some(ProjectionTyCandidate::Select)
} else if selcx.projection_mode() == Reveal::All {
assert!(!poly_trait_ref.needs_infer());
if !poly_trait_ref.needs_subst() {
Some(ProjectionTyCandidate::Select)
} else {
None
}
} else {
None
}
} else {
// This is saying that neither the trait nor
@ -982,11 +988,6 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
};
candidate_set.vec.extend(new_candidate);
}
super::VtableImpl(_) => {
// In trans mode, we can just project out of impls, no prob.
assert!(selcx.projection_mode() == Reveal::All);
candidate_set.vec.push(ProjectionTyCandidate::Select);
}
super::VtableParam(..) => {
// This case tell us nothing about the value of an
// associated type. Consider:

View File

@ -11,6 +11,7 @@
// Tests that `transmute` cannot be called on types of different size.
#![allow(warnings)]
#![feature(specialization)]
use std::mem::transmute;
@ -24,4 +25,15 @@ unsafe fn g<T>(x: &T) {
//~^ ERROR transmute called with differently sized types
}
trait Specializable { type Output; }
impl<T> Specializable for T {
default type Output = u16;
}
unsafe fn specializable<T>(x: u16) -> <T as Specializable>::Output {
transmute(x)
//~^ ERROR transmute called with differently sized types
}
fn main() {}