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:
bors 2017-05-11 16:56:17 +00:00
commit e40beb3af1
3 changed files with 84 additions and 23 deletions

View file

@ -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,

View file

@ -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))
}

View 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 };
}