diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index f0b179fa2e420..f9ffaee81f157 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -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>(&mut self, _: ty::Variance, a: &T, diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index dfa11b9c71a04..bbe682e74bc04 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -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>(&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>, 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)) } diff --git a/src/test/run-pass/issue-41849-variance-req.rs b/src/test/run-pass/issue-41849-variance-req.rs new file mode 100644 index 0000000000000..0557a6ef376b6 --- /dev/null +++ b/src/test/run-pass/issue-41849-variance-req.rs @@ -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 or the MIT license +// , 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 { + f: [X; CAPACITY], +} + +struct B { + f: T, +} + +impl Mul for B { + type Output = Self; + fn mul(self, _rhs: B) -> Self::Output { + self + } +} + +impl Mul for B { + type Output = Self; + fn mul(self, _rhs: usize) -> Self::Output { + self + } +} + +fn main() { + let a = A { f: [1] }; + let _ = B { f: a }; +}