Skip to content

Commit

Permalink
In trait selection, before we create inference variables, try to figure
Browse files Browse the repository at this point in the history
out what types/regions we should use just by matching up the trait
reference from the impl with the trait reference we need. Fixes rust-lang#29844.
  • Loading branch information
nikomatsakis committed Dec 8, 2015
1 parent f0264a0 commit 822a5d3
Show file tree
Hide file tree
Showing 7 changed files with 361 additions and 21 deletions.
22 changes: 18 additions & 4 deletions src/librustc/middle/infer/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,18 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
self.report_and_explain_type_error(trace, &terr);
}
infer::TraitMatch(span) => {
// TODO oh dear god the terribleness
self.tcx.sess.span_err(span, "lifetime mismatch during trait processing");
self.tcx.note_and_explain_region(
"...the impl or where clause references the lifetime",
sub,
"...");
self.tcx.note_and_explain_region(
"...but the lifetime is required",
sup,
"");
}
infer::Reborrow(span) => {
span_err!(self.tcx.sess, span, E0312,
"lifetime of reference outlines \
Expand Down Expand Up @@ -1611,12 +1623,9 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
infer::ExprAssignable(_) => {
"expression is assignable"
}
infer::RelateTraitRefs(_) => {
infer::TraitMatchTypes(_) => {
"traits are compatible"
}
infer::RelateSelfType(_) => {
"self type matches impl self type"
}
infer::RelateOutputImplTypes(_) => {
"trait type parameters matches those \
specified on the impl"
Expand Down Expand Up @@ -1656,6 +1665,11 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
}
}
}
infer::TraitMatch(span) => {
self.tcx.sess.span_note(
span,
"...so that the required trait is satisfied");
}
infer::Reborrow(span) => {
self.tcx.sess.span_note(
span,
Expand Down
25 changes: 16 additions & 9 deletions src/librustc/middle/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,8 @@ pub enum TypeOrigin {
// FIXME(eddyb) #11161 is the original Expr required?
ExprAssignable(Span),

// Relating trait refs when resolving vtables
RelateTraitRefs(Span),

// Relating self types when resolving vtables
RelateSelfType(Span),
// Relating types in an impl
TraitMatchTypes(Span),

// Relating trait type parameters to those found in impl etc
RelateOutputImplTypes(Span),
Expand All @@ -154,10 +151,9 @@ impl TypeOrigin {
fn as_str(&self) -> &'static str {
match self {
&TypeOrigin::Misc(_) |
&TypeOrigin::RelateSelfType(_) |
&TypeOrigin::TraitMatchTypes(_) |
&TypeOrigin::RelateOutputImplTypes(_) |
&TypeOrigin::ExprAssignable(_) => "mismatched types",
&TypeOrigin::RelateTraitRefs(_) => "mismatched traits",
&TypeOrigin::MethodCompatCheck(_) => "method not compatible with trait",
&TypeOrigin::MatchExpressionArm(_, _, source) => match source {
hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
Expand Down Expand Up @@ -205,6 +201,9 @@ pub enum SubregionOrigin<'tcx> {
// error.
RFC1214Subregion(Rc<SubregionOrigin<'tcx>>),

// Arose as part of trait matching
TraitMatch(Span),

// Arose from a subtyping relation
Subtype(TypeTrace<'tcx>),

Expand Down Expand Up @@ -842,6 +841,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.region_vars.add_given(sub, sup);
}

pub fn equate_regions(&self,
origin: SubregionOrigin<'tcx>,
a: ty::Region,
b: ty::Region)
{
self.region_vars.make_eqregion(origin, a, b)
}

pub fn sub_types(&self,
a_is_expected: bool,
origin: TypeOrigin,
Expand Down Expand Up @@ -1546,8 +1553,7 @@ impl TypeOrigin {
MethodCompatCheck(span) => span,
ExprAssignable(span) => span,
Misc(span) => span,
RelateTraitRefs(span) => span,
RelateSelfType(span) => span,
TraitMatchTypes(span) => span,
RelateOutputImplTypes(span) => span,
MatchExpressionArm(match_span, _, _) => match_span,
IfExpression(span) => span,
Expand All @@ -1563,6 +1569,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
match *self {
RFC1214Subregion(ref a) => a.span(),
Subtype(ref a) => a.span(),
TraitMatch(a) => a,
InfStackClosure(a) => a,
InvokeClosure(a) => a,
DerefPointer(a) => a,
Expand Down
4 changes: 4 additions & 0 deletions src/librustc/middle/subst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,10 @@ impl<T> VecPerParamSpace<T> {
&self.get_slice(space)[index]
}

pub fn get_mut(&mut self, space: ParamSpace, index: usize) -> &mut T {
&mut self.get_mut_slice(space)[index]
}

pub fn iter<'a>(&'a self) -> Iter<'a,T> {
self.content.iter()
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ mod project;
mod object_safety;
mod select;
mod structural_impls;
mod ty_match;
mod ty_recur;
mod util;

Expand Down
28 changes: 23 additions & 5 deletions src/librustc/middle/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use super::TraitNotObjectSafe;
use super::RFC1214Warning;
use super::Selection;
use super::SelectionResult;
use super::ty_match;
use super::ty_recur;
use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure,
VtableFnPointer, VtableObject, VtableDefaultImpl};
Expand Down Expand Up @@ -2675,12 +2676,29 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
snapshot);
let skol_obligation_trait_ref = skol_obligation.trait_ref;

let impl_substs = util::fresh_type_vars_for_impl(self.infcx,
obligation.cause.span,
impl_def_id);
let impl_generics = self.tcx().lookup_item_type(impl_def_id).generics;
let impl_substs =
match ty_match::perform_match(self.infcx,
&impl_generics,
obligation.cause.span,
&impl_trait_ref,
&skol_obligation_trait_ref) {
Ok(substs) => substs,
Err(e) => {
debug!("match_impl: perform_match failed due to `{}`", e);
return Err(());
}
};

// TODO Match computation creates a set of substitions, but
// doesn't guarantee that all necessary relations are
// established, particularly with regard to
// projections. Therefore, we also do the subtyping check here
// a second time. Obviously inefficient and suboptimal.
//
// TODO question: is the leak check sufficient now?

let impl_trait_ref = impl_trait_ref.subst(self.tcx(),
&impl_substs);
let impl_trait_ref = impl_trait_ref.subst(self.tcx(), &impl_substs);

let impl_trait_ref =
project::normalize_with_depth(self,
Expand Down
Loading

0 comments on commit 822a5d3

Please sign in to comment.