Skip to content

Commit 5ea536b

Browse files
authored
Rollup merge of #114253 - fmease:compute-variances-for-lazy-ty-aliases, r=oli-obk
Compute variances for lazy type aliases Fixes #114221. CC ``@oli-obk`` r? types
2 parents 576bf82 + 6f5d855 commit 5ea536b

22 files changed

+226
-85
lines changed

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+22-4
Original file line numberDiff line numberDiff line change
@@ -245,13 +245,14 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
245245
}
246246
// `ForeignItem`s are handled separately.
247247
hir::ItemKind::ForeignMod { .. } => {}
248-
hir::ItemKind::TyAlias(hir_ty, ..) => {
248+
hir::ItemKind::TyAlias(hir_ty, ast_generics) => {
249249
if tcx.features().lazy_type_alias
250250
|| tcx.type_of(item.owner_id).skip_binder().has_opaque_types()
251251
{
252252
// Bounds of lazy type aliases and of eager ones that contain opaque types are respected.
253253
// E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`.
254254
check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow);
255+
check_variances_for_type_defn(tcx, item, ast_generics);
255256
}
256257
}
257258
_ => {}
@@ -1700,10 +1701,27 @@ fn check_variances_for_type_defn<'tcx>(
17001701
hir_generics: &hir::Generics<'_>,
17011702
) {
17021703
let identity_args = ty::GenericArgs::identity_for_item(tcx, item.owner_id);
1703-
for field in tcx.adt_def(item.owner_id).all_fields() {
1704-
if field.ty(tcx, identity_args).references_error() {
1705-
return;
1704+
1705+
match item.kind {
1706+
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
1707+
for field in tcx.adt_def(item.owner_id).all_fields() {
1708+
if field.ty(tcx, identity_args).references_error() {
1709+
return;
1710+
}
1711+
}
1712+
}
1713+
ItemKind::TyAlias(..) => {
1714+
let ty = tcx.type_of(item.owner_id).instantiate_identity();
1715+
1716+
if tcx.features().lazy_type_alias || ty.has_opaque_types() {
1717+
if ty.references_error() {
1718+
return;
1719+
}
1720+
} else {
1721+
bug!();
1722+
}
17061723
}
1724+
_ => bug!(),
17071725
}
17081726

17091727
let ty_predicates = tcx.predicates_of(item.owner_id);

compiler/rustc_hir_analysis/src/variance/constraints.rs

+25-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use hir::def_id::{DefId, LocalDefId};
77
use rustc_hir as hir;
88
use rustc_hir::def::DefKind;
9-
use rustc_middle::ty::{self, Ty, TyCtxt};
9+
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
1010
use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
1111

1212
use super::terms::VarianceTerm::*;
@@ -78,6 +78,12 @@ pub fn add_constraints_from_crate<'a, 'tcx>(
7878
}
7979
}
8080
DefKind::Fn | DefKind::AssocFn => constraint_cx.build_constraints_for_item(def_id),
81+
DefKind::TyAlias
82+
if tcx.features().lazy_type_alias
83+
|| tcx.type_of(def_id).instantiate_identity().has_opaque_types() =>
84+
{
85+
constraint_cx.build_constraints_for_item(def_id)
86+
}
8187
_ => {}
8288
}
8389
}
@@ -101,7 +107,18 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
101107

102108
let inferred_start = self.terms_cx.inferred_starts[&def_id];
103109
let current_item = &CurrentItem { inferred_start };
104-
match tcx.type_of(def_id).instantiate_identity().kind() {
110+
let ty = tcx.type_of(def_id).instantiate_identity();
111+
112+
// The type as returned by `type_of` is the underlying type and generally not a weak projection.
113+
// Therefore we need to check the `DefKind` first.
114+
if let DefKind::TyAlias = tcx.def_kind(def_id)
115+
&& (tcx.features().lazy_type_alias || ty.has_opaque_types())
116+
{
117+
self.add_constraints_from_ty(current_item, ty, self.covariant);
118+
return;
119+
}
120+
121+
match ty.kind() {
105122
ty::Adt(def, _) => {
106123
// Not entirely obvious: constraints on structs/enums do not
107124
// affect the variance of their type parameters. See discussion
@@ -127,6 +144,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
127144
}
128145

129146
ty::Error(_) => {}
147+
130148
_ => {
131149
span_bug!(
132150
tcx.def_span(def_id),
@@ -252,10 +270,14 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
252270
self.add_constraints_from_args(current, def.did(), args, variance);
253271
}
254272

255-
ty::Alias(_, ref data) => {
273+
ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, ref data) => {
256274
self.add_constraints_from_invariant_args(current, data.args, variance);
257275
}
258276

277+
ty::Alias(ty::Weak, ref data) => {
278+
self.add_constraints_from_args(current, data.def_id, data.args, variance);
279+
}
280+
259281
ty::Dynamic(data, r, _) => {
260282
// The type `dyn Trait<T> +'a` is covariant w/r/t `'a`:
261283
self.add_constraints_from_region(current, r, variance);

compiler/rustc_hir_analysis/src/variance/mod.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_hir::def::DefKind;
88
use rustc_hir::def_id::{DefId, LocalDefId};
99
use rustc_middle::query::Providers;
1010
use rustc_middle::ty::{self, CrateVariancesMap, GenericArgsRef, Ty, TyCtxt};
11-
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable};
11+
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt};
1212
use std::ops::ControlFlow;
1313

1414
/// 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] {
5656
let crate_map = tcx.crate_variances(());
5757
return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
5858
}
59+
DefKind::TyAlias
60+
if tcx.features().lazy_type_alias
61+
|| tcx.type_of(item_def_id).instantiate_identity().has_opaque_types() =>
62+
{
63+
// These are inferred.
64+
let crate_map = tcx.crate_variances(());
65+
return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
66+
}
5967
DefKind::OpaqueTy => {
6068
return variance_of_opaque(tcx, item_def_id);
6169
}

compiler/rustc_hir_analysis/src/variance/terms.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
use rustc_arena::DroplessArena;
1313
use rustc_hir::def::DefKind;
1414
use rustc_hir::def_id::{LocalDefId, LocalDefIdMap};
15-
use rustc_middle::ty::{self, TyCtxt};
15+
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
1616
use std::fmt;
1717

1818
use self::VarianceTerm::*;
@@ -97,6 +97,12 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(
9797
}
9898
}
9999
DefKind::Fn | DefKind::AssocFn => terms_cx.add_inferreds_for_item(def_id),
100+
DefKind::TyAlias
101+
if tcx.features().lazy_type_alias
102+
|| tcx.type_of(def_id).instantiate_identity().has_opaque_types() =>
103+
{
104+
terms_cx.add_inferreds_for_item(def_id)
105+
}
100106
_ => {}
101107
}
102108
}

compiler/rustc_metadata/src/rmeta/encoder.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use rustc_middle::query::Providers;
3030
use rustc_middle::traits::specialization_graph;
3131
use rustc_middle::ty::codec::TyEncoder;
3232
use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
33+
use rustc_middle::ty::TypeVisitableExt;
3334
use rustc_middle::ty::{self, AssocItemContainer, SymbolName, Ty, TyCtxt};
3435
use rustc_middle::util::common::to_readable_str;
3536
use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
@@ -1034,7 +1035,7 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
10341035
}
10351036
}
10361037

1037-
fn should_encode_variances(def_kind: DefKind) -> bool {
1038+
fn should_encode_variances<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: DefKind) -> bool {
10381039
match def_kind {
10391040
DefKind::Struct
10401041
| DefKind::Union
@@ -1053,7 +1054,6 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
10531054
| DefKind::Static(..)
10541055
| DefKind::Const
10551056
| DefKind::ForeignMod
1056-
| DefKind::TyAlias
10571057
| DefKind::Impl { .. }
10581058
| DefKind::Trait
10591059
| DefKind::TraitAlias
@@ -1067,6 +1067,10 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
10671067
| DefKind::Closure
10681068
| DefKind::Generator
10691069
| DefKind::ExternCrate => false,
1070+
DefKind::TyAlias => {
1071+
tcx.features().lazy_type_alias
1072+
|| tcx.type_of(def_id).instantiate_identity().has_opaque_types()
1073+
}
10701074
}
10711075
}
10721076

@@ -1349,7 +1353,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
13491353
self.encode_default_body_stability(def_id);
13501354
self.encode_deprecation(def_id);
13511355
}
1352-
if should_encode_variances(def_kind) {
1356+
if should_encode_variances(tcx, def_id, def_kind) {
13531357
let v = self.tcx.variances_of(def_id);
13541358
record_array!(self.tables.variances_of[def_id] <- v);
13551359
}

compiler/rustc_middle/src/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -749,7 +749,7 @@ rustc_queries! {
749749
separate_provide_extern
750750
}
751751

752-
/// Gets a map with the variance of every item; use `item_variance` instead.
752+
/// Gets a map with the variance of every item; use `variances_of` instead.
753753
query crate_variances(_: ()) -> &'tcx ty::CrateVariancesMap<'tcx> {
754754
arena_cache
755755
desc { "computing the variances for items in this crate" }

tests/rustdoc-json/type/inherent_associated_type_bound.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
// @set Carrier = '$.index[*][?(@.name=="Carrier")].id'
66
pub struct Carrier<'a>(&'a ());
77

8-
// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.generic_params[*].name' \""'b"\"
9-
// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Carrier
10-
// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].lifetime' \""'b"\"
11-
// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.name' '"Focus"'
12-
// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.trait' null
13-
// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.args.angle_bracketed.args[0].type.primitive' '"i32"'
14-
15-
pub type User = for<'b> fn(Carrier<'b>::Focus<i32>);
8+
// @count "$.index[*][?(@.name=='user')].inner.function.decl.inputs[*]" 1
9+
// @is "$.index[*][?(@.name=='user')].inner.function.decl.inputs[0][0]" '"_"'
10+
// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.generic_params[*].name' \""'b"\"
11+
// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Carrier
12+
// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].lifetime' \""'b"\"
13+
// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.name' '"Focus"'
14+
// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.trait' null
15+
// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.args.angle_bracketed.args[0].type.primitive' '"i32"'
16+
pub fn user(_: for<'b> fn(Carrier<'b>::Focus<i32>)) {}
1617

1718
impl<'a> Carrier<'a> {
1819
pub type Focus<T> = &'a mut T;

tests/rustdoc-json/type/inherent_associated_type_projections.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
// @set Parametrized = '$.index[*][?(@.name=="Parametrized")].id'
66
pub struct Parametrized<T>(T);
77

8-
// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.self_type.resolved_path.id' $Parametrized
9-
// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].type.primitive' \"i32\"
10-
// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.name' '"Proj"'
11-
// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.trait' null
12-
pub type Test = Parametrized<i32>::Proj;
8+
// @count "$.index[*][?(@.name=='test')].inner.function.decl.inputs[*]" 1
9+
// @is "$.index[*][?(@.name=='test')].inner.function.decl.inputs[0][0]" '"_"'
10+
// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Parametrized
11+
// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].type.primitive' \"i32\"
12+
// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.name' '"Proj"'
13+
// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.trait' null
14+
pub fn test(_: Parametrized<i32>::Proj) {}
1315

1416
/// param_bool
1517
impl Parametrized<bool> {

tests/rustdoc/inherent-projections.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ impl Owner {
1313
}
1414

1515
// Make sure we handle bound vars correctly.
16-
// @has 'inherent_projections/type.User.html' '//pre[@class="rust item-decl"]' "for<'a> fn(_: Carrier<'a>::Focus)"
17-
pub type User = for<'a> fn(Carrier<'a>::Focus);
16+
// @has 'inherent_projections/fn.user.html' '//pre[@class="rust item-decl"]' "user(_: for<'a> fn(_: Carrier<'a>::Focus))"
17+
pub fn user(_: for<'a> fn(Carrier<'a>::Focus)) {}
1818

1919
pub struct Carrier<'a>(&'a ());
2020

@@ -27,11 +27,11 @@ impl<'a> Carrier<'a> {
2727
// FIXME(inherent_associated_types): Below we link to `Proj` but we should link to `Proj-1`.
2828
// The current test checks for the buggy behavior for demonstration purposes.
2929

30-
// @has 'inherent_projections/type.Test.html'
31-
// @has - '//pre[@class="rust item-decl"]' "Parametrized<i32>"
30+
// @has 'inherent_projections/fn.test.html'
31+
// @has - '//pre[@class="rust item-decl"]' "test(_: Parametrized<i32>::Proj)"
3232
// @has - '//pre[@class="rust item-decl"]//a[@class="associatedtype"]/@href' 'struct.Parametrized.html#associatedtype.Proj'
3333
// @!has - '//pre[@class="rust item-decl"]//a[@class="associatedtype"]/@href' 'struct.Parametrized.html#associatedtype.Proj-1'
34-
pub type Test = Parametrized<i32>::Proj;
34+
pub fn test(_: Parametrized<i32>::Proj) {}
3535

3636
pub struct Parametrized<T>(T);
3737

tests/ui/associated-inherent-types/issue-111879-0.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@
55

66
pub struct Carrier<'a>(&'a ());
77

8-
pub type User = for<'b> fn(Carrier<'b>::Focus<i32>);
9-
108
impl<'a> Carrier<'a> {
11-
pub type Focus<T> = &'a mut User; //~ ERROR overflow evaluating associated type
9+
pub type Focus<T> = &'a mut for<'b> fn(Carrier<'b>::Focus<i32>); //~ ERROR overflow evaluating associated type
1210
}
1311

1412
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error: overflow evaluating associated type `Carrier<'b>::Focus<i32>`
2-
--> $DIR/issue-111879-0.rs:11:25
2+
--> $DIR/issue-111879-0.rs:9:25
33
|
4-
LL | pub type Focus<T> = &'a mut User;
5-
| ^^^^^^^^^^^^
4+
LL | pub type Focus<T> = &'a mut for<'b> fn(Carrier<'b>::Focus<i32>);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66

77
error: aborting due to previous error
88

tests/ui/associated-inherent-types/late-bound-regions.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
// Test if we correctly normalize `S<'a>::P` with respect to late-bound regions.
55

6-
type Function = for<'a> fn(&'a i32) -> S<'a>::P;
7-
86
struct S<'a>(&'a ());
97

108
trait Inter {
@@ -16,7 +14,7 @@ impl<'a> S<'a> {
1614
}
1715

1816
fn ret_ref_local<'e>() -> &'e i32 {
19-
let f: Function = |x| x;
17+
let f: for<'a> fn(&'a i32) -> S<'a>::P = |x| x;
2018

2119
let local = 0;
2220
f(&local) //~ ERROR cannot return value referencing local variable `local`

tests/ui/associated-inherent-types/late-bound-regions.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0515]: cannot return value referencing local variable `local`
2-
--> $DIR/late-bound-regions.rs:22:5
2+
--> $DIR/late-bound-regions.rs:20:5
33
|
44
LL | f(&local)
55
| ^^------^

tests/ui/associated-inherent-types/not-found-self-type-differs.alias.stderr

-16
This file was deleted.

tests/ui/associated-inherent-types/not-found-self-type-differs.local.stderr

-16
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// revisions: local alias
2-
31
#![feature(inherent_associated_types)]
42
#![allow(incomplete_features)]
53

@@ -13,10 +11,7 @@ impl<T> Family<Result<T, ()>> {
1311
type Proj = Self;
1412
}
1513

16-
#[cfg(alias)]
17-
type Alias = Family<Option<()>>::Proj; //[alias]~ ERROR associated type `Proj` not found for `Family<Option<()>>`
18-
1914
fn main() {
20-
#[cfg(local)]
21-
let _: Family<std::path::PathBuf>::Proj = (); //[local]~ ERROR associated type `Proj` not found for `Family<PathBuf>`
15+
let _: Family<Option<()>>::Proj; //~ ERROR associated type `Proj` not found for `Family<Option<()>>`
16+
let _: Family<std::path::PathBuf>::Proj = (); //~ ERROR associated type `Proj` not found for `Family<PathBuf>`
2217
}

0 commit comments

Comments
 (0)