Skip to content

Commit

Permalink
Auto merge of #41913 - nikomatsakis:issue-41849-variance-cycle, r=eddyb
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed May 11, 2017
2 parents 2cc3358 + d22d1fe commit e40beb3
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 23 deletions.
21 changes: 20 additions & 1 deletion src/librustc/infer/equate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -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,
Expand Down
43 changes: 21 additions & 22 deletions src/librustc/ty/relate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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>,
Expand Down Expand Up @@ -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 })
}
}
Expand All @@ -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 })
}
}
Expand Down Expand Up @@ -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))
}

Expand Down
43 changes: 43 additions & 0 deletions src/test/run-pass/issue-41849-variance-req.rs
Original file line number Diff line number Diff line change
@@ -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 };
}

0 comments on commit e40beb3

Please sign in to comment.