Skip to content

Commit a30c932

Browse files
committed
do not fetch variance for items when equating
Fixes #41849. Problem was that evaluating the constant expression required evaluating a trait, which would equate types, which would request variance information, which it would then discard. However, computing the variance information would require determining the type of a field, which would evaluate the constant expression. (This problem will potentially arise *later* as we move to more sophisticated constants, however, where we need to check subtyping. We can tackle that when we come to it.)
1 parent 087d737 commit a30c932

File tree

4 files changed

+98
-31
lines changed

4 files changed

+98
-31
lines changed

src/librustc/infer/combine.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -350,8 +350,14 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
350350
// (e.g. #41849).
351351
relate::relate_substs(self, None, a_subst, b_subst)
352352
} else {
353-
let opt_variances = self.tcx().variances_of(item_def_id);
354-
relate::relate_substs(self, Some(&opt_variances), a_subst, b_subst)
353+
let variances;
354+
let opt_variances = if self.tcx().variance_computed.get() {
355+
variances = self.tcx().item_variances(item_def_id);
356+
Some(&*variances)
357+
} else {
358+
None
359+
};
360+
relate::relate_substs(self, opt_variances, a_subst, b_subst)
355361
}
356362
}
357363

src/librustc/infer/equate.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@
1111
use super::combine::{CombineFields, RelationDir};
1212
use super::{Subtype};
1313

14+
use hir::def_id::DefId;
15+
1416
use ty::{self, Ty, TyCtxt};
1517
use ty::TyVar;
16-
use ty::relate::{Relate, RelateResult, TypeRelation};
18+
use ty::subst::Substs;
19+
use ty::relate::{self, Relate, RelateResult, TypeRelation};
1720

1821
/// Ensures `a` is made equal to `b`. Returns `a` on success.
1922
pub struct Equate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
@@ -38,6 +41,22 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
3841

3942
fn a_is_expected(&self) -> bool { self.a_is_expected }
4043

44+
fn relate_item_substs(&mut self,
45+
_item_def_id: DefId,
46+
a_subst: &'tcx Substs<'tcx>,
47+
b_subst: &'tcx Substs<'tcx>)
48+
-> RelateResult<'tcx, &'tcx Substs<'tcx>>
49+
{
50+
// NB: Once we are equating types, we don't care about
51+
// variance, so don't try to lookup the variance here. This
52+
// also avoids some cycles (e.g. #41849) since looking up
53+
// variance requires computing types which can require
54+
// performing trait matching (which then performs equality
55+
// unification).
56+
57+
relate::relate_substs(self, None, a_subst, b_subst)
58+
}
59+
4160
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
4261
_: ty::Variance,
4362
a: &T,

src/librustc/ty/relate.rs

+27-28
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,30 @@ pub trait TypeRelation<'a, 'gcx: 'a+'tcx, 'tcx: 'a> : Sized {
5151
Relate::relate(self, a, b)
5252
}
5353

54+
/// Relate the two substitutions for the given item. The default
55+
/// is to look up the variance for the item and proceed
56+
/// accordingly.
57+
fn relate_item_substs(&mut self,
58+
item_def_id: DefId,
59+
a_subst: &'tcx Substs<'tcx>,
60+
b_subst: &'tcx Substs<'tcx>)
61+
-> RelateResult<'tcx, &'tcx Substs<'tcx>>
62+
{
63+
debug!("relate_item_substs(item_def_id={:?}, a_subst={:?}, b_subst={:?})",
64+
item_def_id,
65+
a_subst,
66+
b_subst);
67+
68+
let variances;
69+
let opt_variances = if self.tcx().variance_computed.get() {
70+
variances = self.tcx().item_variances(item_def_id);
71+
Some(&*variances)
72+
} else {
73+
None
74+
};
75+
relate_substs(self, opt_variances, a_subst, b_subst)
76+
}
77+
5478
/// Switch variance for the purpose of relating `a` and `b`.
5579
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
5680
variance: ty::Variance,
@@ -109,31 +133,6 @@ impl<'tcx> Relate<'tcx> for ty::TypeAndMut<'tcx> {
109133
}
110134
}
111135

112-
// substitutions are not themselves relatable without more context,
113-
// but they is an important subroutine for things that ARE relatable,
114-
// like traits etc.
115-
fn relate_item_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
116-
item_def_id: DefId,
117-
a_subst: &'tcx Substs<'tcx>,
118-
b_subst: &'tcx Substs<'tcx>)
119-
-> RelateResult<'tcx, &'tcx Substs<'tcx>>
120-
where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
121-
{
122-
debug!("substs: item_def_id={:?} a_subst={:?} b_subst={:?}",
123-
item_def_id,
124-
a_subst,
125-
b_subst);
126-
127-
let variances;
128-
let opt_variances = if relation.tcx().variance_computed.get() {
129-
variances = relation.tcx().item_variances(item_def_id);
130-
Some(&*variances)
131-
} else {
132-
None
133-
};
134-
relate_substs(relation, opt_variances, a_subst, b_subst)
135-
}
136-
137136
pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
138137
variances: Option<&Vec<ty::Variance>>,
139138
a_subst: &'tcx Substs<'tcx>,
@@ -297,7 +296,7 @@ impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> {
297296
if a.def_id != b.def_id {
298297
Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
299298
} else {
300-
let substs = relate_item_substs(relation, a.def_id, a.substs, b.substs)?;
299+
let substs = relation.relate_item_substs(a.def_id, a.substs, b.substs)?;
301300
Ok(ty::TraitRef { def_id: a.def_id, substs: substs })
302301
}
303302
}
@@ -314,7 +313,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> {
314313
if a.def_id != b.def_id {
315314
Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
316315
} else {
317-
let substs = relate_item_substs(relation, a.def_id, a.substs, b.substs)?;
316+
let substs = relation.relate_item_substs(a.def_id, a.substs, b.substs)?;
318317
Ok(ty::ExistentialTraitRef { def_id: a.def_id, substs: substs })
319318
}
320319
}
@@ -378,7 +377,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
378377
(&ty::TyAdt(a_def, a_substs), &ty::TyAdt(b_def, b_substs))
379378
if a_def == b_def =>
380379
{
381-
let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?;
380+
let substs = relation.relate_item_substs(a_def.did, a_substs, b_substs)?;
382381
Ok(tcx.mk_adt(a_def, substs))
383382
}
384383

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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+
// Regression test for #41849.
12+
13+
use std::ops::Mul;
14+
15+
const C: usize = 1;
16+
const CAPACITY: usize = 1 * C;
17+
18+
struct A<X> {
19+
f: [X; CAPACITY],
20+
}
21+
22+
struct B<T> {
23+
f: T,
24+
}
25+
26+
impl<T> Mul for B<T> {
27+
type Output = Self;
28+
fn mul(self, _rhs: B<T>) -> Self::Output {
29+
self
30+
}
31+
}
32+
33+
impl<T> Mul<usize> for B<T> {
34+
type Output = Self;
35+
fn mul(self, _rhs: usize) -> Self::Output {
36+
self
37+
}
38+
}
39+
40+
fn main() {
41+
let a = A { f: [1] };
42+
let _ = B { f: a };
43+
}

0 commit comments

Comments
 (0)