Skip to content

Commit ac919fc

Browse files
authoredNov 3, 2016
Auto merge of #37541 - nikomatsakis:issue-37291, r=brson
Use impl obligations as initial environment for specialization This corrects a small regression in specialization that crept in, I think as part of the refactoring to introduce arenas. I also made an experiment (in the last commit) to cleanup the code to be more aggressive about normalization. As the commit log notes, I am not 100% sure that this is correct, but it feels safer, and I think that at worst it yields *more* ICEs (as opposed to admitting faulty code). I'll schedule a crater run to check beyond the testbase. Fixes #37291. r? @aturon
2 parents f9f45c6 + b4f910d commit ac919fc

File tree

3 files changed

+97
-21
lines changed

3 files changed

+97
-21
lines changed
 

‎src/librustc/traits/specialize/mod.rs

+16-21
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use hir::def_id::DefId;
2525
use infer::{InferCtxt, TypeOrigin};
2626
use middle::region;
2727
use ty::subst::{Subst, Substs};
28-
use traits::{self, Reveal, ObligationCause, Normalized};
28+
use traits::{self, Reveal, ObligationCause};
2929
use ty::{self, TyCtxt, TypeFoldable};
3030
use syntax_pos::DUMMY_SP;
3131

@@ -148,6 +148,8 @@ pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
148148
pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
149149
impl1_def_id: DefId,
150150
impl2_def_id: DefId) -> bool {
151+
debug!("specializes({:?}, {:?})", impl1_def_id, impl2_def_id);
152+
151153
if let Some(r) = tcx.specializes_cache.borrow().check(impl1_def_id, impl2_def_id) {
152154
return r;
153155
}
@@ -177,31 +179,24 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
177179
}
178180

179181
// create a parameter environment corresponding to a (skolemized) instantiation of impl1
180-
let mut penv = tcx.construct_parameter_environment(DUMMY_SP,
181-
impl1_def_id,
182-
region::DUMMY_CODE_EXTENT);
182+
let penv = tcx.construct_parameter_environment(DUMMY_SP,
183+
impl1_def_id,
184+
region::DUMMY_CODE_EXTENT);
183185
let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id)
184186
.unwrap()
185187
.subst(tcx, &penv.free_substs);
186188

187-
let result = tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|mut infcx| {
188-
// Normalize the trait reference, adding any obligations
189-
// that arise into the impl1 assumptions.
190-
let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = {
191-
let selcx = &mut SelectionContext::new(&infcx);
192-
traits::normalize(selcx, ObligationCause::dummy(), &impl1_trait_ref)
193-
};
194-
penv.caller_bounds.extend(normalization_obligations.into_iter().map(|o| {
195-
match tcx.lift_to_global(&o.predicate) {
196-
Some(predicate) => predicate,
197-
None => {
198-
bug!("specializes: obligation `{:?}` has inference types/regions", o);
189+
// Create a infcx, taking the predicates of impl1 as assumptions:
190+
let result = tcx.infer_ctxt(None, Some(penv), Reveal::ExactMatch).enter(|infcx| {
191+
// Normalize the trait reference. The WF rules ought to ensure
192+
// that this always succeeds.
193+
let impl1_trait_ref =
194+
match traits::fully_normalize(&infcx, ObligationCause::dummy(), &impl1_trait_ref) {
195+
Ok(impl1_trait_ref) => impl1_trait_ref,
196+
Err(err) => {
197+
bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err);
199198
}
200-
}
201-
}));
202-
203-
// Install the parameter environment, taking the predicates of impl1 as assumptions:
204-
infcx.parameter_environment = penv;
199+
};
205200

206201
// Attempt to prove that impl2 applies, given all of the above.
207202
fulfill_implication(&infcx, impl1_trait_ref, impl2_def_id).is_ok()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![crate_type = "lib"]
12+
13+
use std::ops::Mul;
14+
15+
pub trait A {}
16+
pub trait B {
17+
type AT: A;
18+
}
19+
pub trait C {
20+
type BT: B;
21+
}
22+
23+
pub struct AV;
24+
impl A for AV {}
25+
26+
pub struct BV;
27+
impl B for BV {
28+
type AT = AV;
29+
}
30+
31+
pub struct CV;
32+
impl C for CV {
33+
type BT = BV;
34+
}
35+
36+
pub struct WrapperB<T>(pub T);
37+
pub struct WrapperC<T>(pub T);
38+
39+
impl<C1> Mul<WrapperB<<C1::BT as B>::AT>> for WrapperC<C1>
40+
where C1: C
41+
{
42+
type Output = u8;
43+
fn mul(self, _: WrapperB<<C1::BT as B>::AT>) -> Self::Output {
44+
loop {}
45+
}
46+
}
47+
impl<C1> Mul<WrapperC<C1>> for WrapperC<C1> {
48+
type Output = u8;
49+
fn mul(self, _: WrapperC<C1>) -> Self::Output {
50+
loop {}
51+
}
52+
}

‎src/test/run-pass/issue-37291/main.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// aux-build:lib.rs
12+
13+
// Regression test for #37291. The problem was that the starting
14+
// environment for a specialization check was not including the
15+
// where-clauses from the impl when attempting to normalize the impl's
16+
// trait-ref, so things like `<C as Foo>::Item` could not resolve,
17+
// since the `C: Foo` trait bound was not included in the environment.
18+
19+
extern crate lib;
20+
21+
use lib::{CV, WrapperB, WrapperC};
22+
23+
fn main() {
24+
let a = WrapperC(CV);
25+
let b = WrapperC(CV);
26+
if false {
27+
let _ = a * b;
28+
}
29+
}

0 commit comments

Comments
 (0)
Please sign in to comment.