Compute variances for lazy type aliases
This commit is contained in:
parent
8131b9774e
commit
263a0dec60
@ -245,13 +245,14 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
}
|
||||
// `ForeignItem`s are handled separately.
|
||||
hir::ItemKind::ForeignMod { .. } => {}
|
||||
hir::ItemKind::TyAlias(hir_ty, ..) => {
|
||||
hir::ItemKind::TyAlias(hir_ty, ast_generics) => {
|
||||
if tcx.features().lazy_type_alias
|
||||
|| tcx.type_of(item.owner_id).skip_binder().has_opaque_types()
|
||||
{
|
||||
// Bounds of lazy type aliases and of eager ones that contain opaque types are respected.
|
||||
// E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`.
|
||||
check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow);
|
||||
check_variances_for_type_defn(tcx, item, ast_generics);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@ -1700,10 +1701,27 @@ fn check_variances_for_type_defn<'tcx>(
|
||||
hir_generics: &hir::Generics<'_>,
|
||||
) {
|
||||
let identity_args = ty::GenericArgs::identity_for_item(tcx, item.owner_id);
|
||||
for field in tcx.adt_def(item.owner_id).all_fields() {
|
||||
if field.ty(tcx, identity_args).references_error() {
|
||||
return;
|
||||
|
||||
match item.kind {
|
||||
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
|
||||
for field in tcx.adt_def(item.owner_id).all_fields() {
|
||||
if field.ty(tcx, identity_args).references_error() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
ItemKind::TyAlias(..) => {
|
||||
let ty = tcx.type_of(item.owner_id).instantiate_identity();
|
||||
|
||||
if tcx.features().lazy_type_alias || ty.has_opaque_types() {
|
||||
if ty.references_error() {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
bug!();
|
||||
}
|
||||
}
|
||||
_ => bug!(),
|
||||
}
|
||||
|
||||
let ty_predicates = tcx.predicates_of(item.owner_id);
|
||||
|
@ -6,7 +6,7 @@
|
||||
use hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
|
||||
|
||||
use super::terms::VarianceTerm::*;
|
||||
@ -78,6 +78,12 @@ pub fn add_constraints_from_crate<'a, 'tcx>(
|
||||
}
|
||||
}
|
||||
DefKind::Fn | DefKind::AssocFn => constraint_cx.build_constraints_for_item(def_id),
|
||||
DefKind::TyAlias
|
||||
if tcx.features().lazy_type_alias
|
||||
|| tcx.type_of(def_id).instantiate_identity().has_opaque_types() =>
|
||||
{
|
||||
constraint_cx.build_constraints_for_item(def_id)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -101,7 +107,18 @@ fn build_constraints_for_item(&mut self, def_id: LocalDefId) {
|
||||
|
||||
let inferred_start = self.terms_cx.inferred_starts[&def_id];
|
||||
let current_item = &CurrentItem { inferred_start };
|
||||
match tcx.type_of(def_id).instantiate_identity().kind() {
|
||||
let ty = tcx.type_of(def_id).instantiate_identity();
|
||||
|
||||
// The type as returned by `type_of` is the underlying type and generally not a weak projection.
|
||||
// Therefore we need to check the `DefKind` first.
|
||||
if let DefKind::TyAlias = tcx.def_kind(def_id)
|
||||
&& (tcx.features().lazy_type_alias || ty.has_opaque_types())
|
||||
{
|
||||
self.add_constraints_from_ty(current_item, ty, self.covariant);
|
||||
return;
|
||||
}
|
||||
|
||||
match ty.kind() {
|
||||
ty::Adt(def, _) => {
|
||||
// Not entirely obvious: constraints on structs/enums do not
|
||||
// affect the variance of their type parameters. See discussion
|
||||
@ -127,6 +144,7 @@ fn build_constraints_for_item(&mut self, def_id: LocalDefId) {
|
||||
}
|
||||
|
||||
ty::Error(_) => {}
|
||||
|
||||
_ => {
|
||||
span_bug!(
|
||||
tcx.def_span(def_id),
|
||||
@ -252,10 +270,14 @@ fn add_constraints_from_ty(
|
||||
self.add_constraints_from_args(current, def.did(), args, variance);
|
||||
}
|
||||
|
||||
ty::Alias(_, ref data) => {
|
||||
ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, ref data) => {
|
||||
self.add_constraints_from_invariant_args(current, data.args, variance);
|
||||
}
|
||||
|
||||
ty::Alias(ty::Weak, ref data) => {
|
||||
self.add_constraints_from_args(current, data.def_id, data.args, variance);
|
||||
}
|
||||
|
||||
ty::Dynamic(data, r, _) => {
|
||||
// The type `dyn Trait<T> +'a` is covariant w/r/t `'a`:
|
||||
self.add_constraints_from_region(current, r, variance);
|
||||
|
@ -8,7 +8,7 @@
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{self, CrateVariancesMap, GenericArgsRef, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable};
|
||||
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt};
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
/// Defines the `TermsContext` basically houses an arena where we can
|
||||
@ -56,6 +56,14 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
|
||||
let crate_map = tcx.crate_variances(());
|
||||
return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
|
||||
}
|
||||
DefKind::TyAlias
|
||||
if tcx.features().lazy_type_alias
|
||||
|| tcx.type_of(item_def_id).instantiate_identity().has_opaque_types() =>
|
||||
{
|
||||
// These are inferred.
|
||||
let crate_map = tcx.crate_variances(());
|
||||
return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
|
||||
}
|
||||
DefKind::OpaqueTy => {
|
||||
return variance_of_opaque(tcx, item_def_id);
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
use rustc_arena::DroplessArena;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{LocalDefId, LocalDefIdMap};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
|
||||
use std::fmt;
|
||||
|
||||
use self::VarianceTerm::*;
|
||||
@ -97,6 +97,12 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(
|
||||
}
|
||||
}
|
||||
DefKind::Fn | DefKind::AssocFn => terms_cx.add_inferreds_for_item(def_id),
|
||||
DefKind::TyAlias
|
||||
if tcx.features().lazy_type_alias
|
||||
|| tcx.type_of(def_id).instantiate_identity().has_opaque_types() =>
|
||||
{
|
||||
terms_cx.add_inferreds_for_item(def_id)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@
|
||||
use rustc_middle::traits::specialization_graph;
|
||||
use rustc_middle::ty::codec::TyEncoder;
|
||||
use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
|
||||
use rustc_middle::ty::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, AssocItemContainer, SymbolName, Ty, TyCtxt};
|
||||
use rustc_middle::util::common::to_readable_str;
|
||||
use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
|
||||
@ -1034,7 +1035,7 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
|
||||
}
|
||||
}
|
||||
|
||||
fn should_encode_variances(def_kind: DefKind) -> bool {
|
||||
fn should_encode_variances<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: DefKind) -> bool {
|
||||
match def_kind {
|
||||
DefKind::Struct
|
||||
| DefKind::Union
|
||||
@ -1053,7 +1054,6 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
|
||||
| DefKind::Static(..)
|
||||
| DefKind::Const
|
||||
| DefKind::ForeignMod
|
||||
| DefKind::TyAlias
|
||||
| DefKind::Impl { .. }
|
||||
| DefKind::Trait
|
||||
| DefKind::TraitAlias
|
||||
@ -1067,6 +1067,10 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
|
||||
| DefKind::Closure
|
||||
| DefKind::Generator
|
||||
| DefKind::ExternCrate => false,
|
||||
DefKind::TyAlias => {
|
||||
tcx.features().lazy_type_alias
|
||||
|| tcx.type_of(def_id).instantiate_identity().has_opaque_types()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1349,7 +1353,7 @@ fn encode_def_ids(&mut self) {
|
||||
self.encode_default_body_stability(def_id);
|
||||
self.encode_deprecation(def_id);
|
||||
}
|
||||
if should_encode_variances(def_kind) {
|
||||
if should_encode_variances(tcx, def_id, def_kind) {
|
||||
let v = self.tcx.variances_of(def_id);
|
||||
record_array!(self.tables.variances_of[def_id] <- v);
|
||||
}
|
||||
|
@ -749,7 +749,7 @@
|
||||
separate_provide_extern
|
||||
}
|
||||
|
||||
/// Gets a map with the variance of every item; use `item_variance` instead.
|
||||
/// Gets a map with the variance of every item; use `variances_of` instead.
|
||||
query crate_variances(_: ()) -> &'tcx ty::CrateVariancesMap<'tcx> {
|
||||
arena_cache
|
||||
desc { "computing the variances for items in this crate" }
|
||||
|
38
tests/ui/lazy-type-alias/variance.rs
Normal file
38
tests/ui/lazy-type-alias/variance.rs
Normal file
@ -0,0 +1,38 @@
|
||||
// This is a regression test for issue #114221.
|
||||
// Check that we compute variances for lazy type aliases.
|
||||
|
||||
// check-pass
|
||||
|
||||
#![feature(lazy_type_alias)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// [+] `A` is covariant over `'a`.
|
||||
struct A<'a>(Co<'a>);
|
||||
|
||||
// [+] `Co` is covariant over `'a`.
|
||||
type Co<'a> = &'a ();
|
||||
|
||||
fn co<'a>(x: A<'static>) {
|
||||
let _: A<'a> = x;
|
||||
}
|
||||
|
||||
// [-] `B` is contravariant over `'a`.
|
||||
struct B<'a>(Contra<'a>);
|
||||
|
||||
// [-] `Contra` is contravariant over `'a`.
|
||||
type Contra<'a> = fn(&'a ());
|
||||
|
||||
fn contra<'a>(x: B<'a>) {
|
||||
let _: B<'static> = x;
|
||||
}
|
||||
|
||||
struct C<T, U>(CoContra<T, U>);
|
||||
|
||||
// [+, -] `CoContra` is covariant over `T` and contravariant over `U`.
|
||||
type CoContra<T, U> = Option<(T, fn(U))>;
|
||||
|
||||
fn co_contra<'a>(x: C<&'static (), &'a ()>) -> C<&'a (), &'static ()> {
|
||||
x
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user