Auto merge of #41913 - nikomatsakis:issue-41849-variance-cycle, r=eddyb
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.) r? @eddyb
This commit is contained in:
commit
e40beb3af1
3 changed files with 84 additions and 23 deletions
|
|
@ -11,9 +11,12 @@
|
|||
use super::combine::{CombineFields, RelationDir};
|
||||
use super::{Subtype};
|
||||
|
||||
use hir::def_id::DefId;
|
||||
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::TyVar;
|
||||
use ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use ty::subst::Substs;
|
||||
use ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||
|
||||
/// Ensures `a` is made equal to `b`. Returns `a` on success.
|
||||
pub struct Equate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
|
||||
|
|
@ -38,6 +41,22 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
|
|||
|
||||
fn a_is_expected(&self) -> bool { self.a_is_expected }
|
||||
|
||||
fn relate_item_substs(&mut self,
|
||||
_item_def_id: DefId,
|
||||
a_subst: &'tcx Substs<'tcx>,
|
||||
b_subst: &'tcx Substs<'tcx>)
|
||||
-> RelateResult<'tcx, &'tcx Substs<'tcx>>
|
||||
{
|
||||
// NB: Once we are equating types, we don't care about
|
||||
// variance, so don't try to lookup the variance here. This
|
||||
// also avoids some cycles (e.g. #41849) since looking up
|
||||
// variance requires computing types which can require
|
||||
// performing trait matching (which then performs equality
|
||||
// unification).
|
||||
|
||||
relate::relate_substs(self, None, a_subst, b_subst)
|
||||
}
|
||||
|
||||
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
|
||||
_: ty::Variance,
|
||||
a: &T,
|
||||
|
|
|
|||
|
|
@ -51,6 +51,24 @@ pub trait TypeRelation<'a, 'gcx: 'a+'tcx, 'tcx: 'a> : Sized {
|
|||
Relate::relate(self, a, b)
|
||||
}
|
||||
|
||||
/// Relate the two substitutions for the given item. The default
|
||||
/// is to look up the variance for the item and proceed
|
||||
/// accordingly.
|
||||
fn relate_item_substs(&mut self,
|
||||
item_def_id: DefId,
|
||||
a_subst: &'tcx Substs<'tcx>,
|
||||
b_subst: &'tcx Substs<'tcx>)
|
||||
-> RelateResult<'tcx, &'tcx Substs<'tcx>>
|
||||
{
|
||||
debug!("relate_item_substs(item_def_id={:?}, a_subst={:?}, b_subst={:?})",
|
||||
item_def_id,
|
||||
a_subst,
|
||||
b_subst);
|
||||
|
||||
let opt_variances = self.tcx().variances_of(item_def_id);
|
||||
relate_substs(self, Some(&opt_variances), a_subst, b_subst)
|
||||
}
|
||||
|
||||
/// Switch variance for the purpose of relating `a` and `b`.
|
||||
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
|
||||
variance: ty::Variance,
|
||||
|
|
@ -109,25 +127,6 @@ impl<'tcx> Relate<'tcx> for ty::TypeAndMut<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// substitutions are not themselves relatable without more context,
|
||||
// but they is an important subroutine for things that ARE relatable,
|
||||
// like traits etc.
|
||||
fn relate_item_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
|
||||
item_def_id: DefId,
|
||||
a_subst: &'tcx Substs<'tcx>,
|
||||
b_subst: &'tcx Substs<'tcx>)
|
||||
-> RelateResult<'tcx, &'tcx Substs<'tcx>>
|
||||
where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
|
||||
{
|
||||
debug!("substs: item_def_id={:?} a_subst={:?} b_subst={:?}",
|
||||
item_def_id,
|
||||
a_subst,
|
||||
b_subst);
|
||||
|
||||
let opt_variances = relation.tcx().variances_of(item_def_id);
|
||||
relate_substs(relation, Some(&opt_variances), a_subst, b_subst)
|
||||
}
|
||||
|
||||
pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
|
||||
variances: Option<&Vec<ty::Variance>>,
|
||||
a_subst: &'tcx Substs<'tcx>,
|
||||
|
|
@ -291,7 +290,7 @@ impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> {
|
|||
if a.def_id != b.def_id {
|
||||
Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
|
||||
} else {
|
||||
let substs = relate_item_substs(relation, a.def_id, a.substs, b.substs)?;
|
||||
let substs = relation.relate_item_substs(a.def_id, a.substs, b.substs)?;
|
||||
Ok(ty::TraitRef { def_id: a.def_id, substs: substs })
|
||||
}
|
||||
}
|
||||
|
|
@ -308,7 +307,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> {
|
|||
if a.def_id != b.def_id {
|
||||
Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
|
||||
} else {
|
||||
let substs = relate_item_substs(relation, a.def_id, a.substs, b.substs)?;
|
||||
let substs = relation.relate_item_substs(a.def_id, a.substs, b.substs)?;
|
||||
Ok(ty::ExistentialTraitRef { def_id: a.def_id, substs: substs })
|
||||
}
|
||||
}
|
||||
|
|
@ -372,7 +371,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
|
|||
(&ty::TyAdt(a_def, a_substs), &ty::TyAdt(b_def, b_substs))
|
||||
if a_def == b_def =>
|
||||
{
|
||||
let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?;
|
||||
let substs = relation.relate_item_substs(a_def.did, a_substs, b_substs)?;
|
||||
Ok(tcx.mk_adt(a_def, substs))
|
||||
}
|
||||
|
||||
|
|
|
|||
43
src/test/run-pass/issue-41849-variance-req.rs
Normal file
43
src/test/run-pass/issue-41849-variance-req.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Regression test for #41849.
|
||||
|
||||
use std::ops::Mul;
|
||||
|
||||
const C: usize = 1;
|
||||
const CAPACITY: usize = 1 * C;
|
||||
|
||||
struct A<X> {
|
||||
f: [X; CAPACITY],
|
||||
}
|
||||
|
||||
struct B<T> {
|
||||
f: T,
|
||||
}
|
||||
|
||||
impl<T> Mul for B<T> {
|
||||
type Output = Self;
|
||||
fn mul(self, _rhs: B<T>) -> Self::Output {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Mul<usize> for B<T> {
|
||||
type Output = Self;
|
||||
fn mul(self, _rhs: usize) -> Self::Output {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = A { f: [1] };
|
||||
let _ = B { f: a };
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue