Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compute variances for lazy type aliases #114253

Merged
merged 2 commits into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
_ => {}
Expand Down Expand Up @@ -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);
Expand Down
28 changes: 25 additions & 3 deletions compiler/rustc_hir_analysis/src/variance/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down Expand Up @@ -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)
}
_ => {}
}
}
Expand All @@ -101,7 +107,18 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {

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
Expand All @@ -127,6 +144,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
}

ty::Error(_) => {}

_ => {
span_bug!(
tcx.def_span(def_id),
Expand Down Expand Up @@ -252,10 +270,14 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
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);
Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_hir_analysis/src/variance/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc_hir::def::DefKind;
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
Expand Down Expand Up @@ -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);
}
Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_hir_analysis/src/variance/terms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down Expand Up @@ -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)
}
_ => {}
}
}
Expand Down
10 changes: 7 additions & 3 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use rustc_middle::query::Providers;
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};
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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()
}
}
}

Expand Down Expand Up @@ -1349,7 +1353,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
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);
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,7 @@ rustc_queries! {
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" }
Expand Down
17 changes: 9 additions & 8 deletions tests/rustdoc-json/type/inherent_associated_type_bound.rs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this test affected? It has neither opaque types nor the lazy type alias feature gate

Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
// @set Carrier = '$.index[*][?(@.name=="Carrier")].id'
pub struct Carrier<'a>(&'a ());

// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.generic_params[*].name' \""'b"\"
// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Carrier
// @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"\"
// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.name' '"Focus"'
// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.trait' null
// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.args.angle_bracketed.args[0].type.primitive' '"i32"'

pub type User = for<'b> fn(Carrier<'b>::Focus<i32>);
// @count "$.index[*][?(@.name=='user')].inner.function.decl.inputs[*]" 1
// @is "$.index[*][?(@.name=='user')].inner.function.decl.inputs[0][0]" '"_"'
// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.generic_params[*].name' \""'b"\"
// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Carrier
// @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"\"
// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.name' '"Focus"'
// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.trait' null
// @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"'
pub fn user(_: for<'b> fn(Carrier<'b>::Focus<i32>)) {}

impl<'a> Carrier<'a> {
pub type Focus<T> = &'a mut T;
Expand Down
12 changes: 7 additions & 5 deletions tests/rustdoc-json/type/inherent_associated_type_projections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
// @set Parametrized = '$.index[*][?(@.name=="Parametrized")].id'
pub struct Parametrized<T>(T);

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

/// param_bool
impl Parametrized<bool> {
Expand Down
10 changes: 5 additions & 5 deletions tests/rustdoc/inherent-projections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ impl Owner {
}

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

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

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

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

pub struct Parametrized<T>(T);

Expand Down
4 changes: 1 addition & 3 deletions tests/ui/associated-inherent-types/issue-111879-0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@

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

pub type User = for<'b> fn(Carrier<'b>::Focus<i32>);

impl<'a> Carrier<'a> {
pub type Focus<T> = &'a mut User; //~ ERROR overflow evaluating associated type
pub type Focus<T> = &'a mut for<'b> fn(Carrier<'b>::Focus<i32>); //~ ERROR overflow evaluating associated type
}

fn main() {}
6 changes: 3 additions & 3 deletions tests/ui/associated-inherent-types/issue-111879-0.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: overflow evaluating associated type `Carrier<'b>::Focus<i32>`
--> $DIR/issue-111879-0.rs:11:25
--> $DIR/issue-111879-0.rs:9:25
|
LL | pub type Focus<T> = &'a mut User;
| ^^^^^^^^^^^^
LL | pub type Focus<T> = &'a mut for<'b> fn(Carrier<'b>::Focus<i32>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

4 changes: 1 addition & 3 deletions tests/ui/associated-inherent-types/late-bound-regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

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

type Function = for<'a> fn(&'a i32) -> S<'a>::P;

struct S<'a>(&'a ());

trait Inter {
Expand All @@ -16,7 +14,7 @@ impl<'a> S<'a> {
}

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

let local = 0;
f(&local) //~ ERROR cannot return value referencing local variable `local`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0515]: cannot return value referencing local variable `local`
--> $DIR/late-bound-regions.rs:22:5
--> $DIR/late-bound-regions.rs:20:5
|
LL | f(&local)
| ^^------^
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// revisions: local alias

#![feature(inherent_associated_types)]
#![allow(incomplete_features)]

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

#[cfg(alias)]
type Alias = Family<Option<()>>::Proj; //[alias]~ ERROR associated type `Proj` not found for `Family<Option<()>>`

fn main() {
#[cfg(local)]
let _: Family<std::path::PathBuf>::Proj = (); //[local]~ ERROR associated type `Proj` not found for `Family<PathBuf>`
let _: Family<Option<()>>::Proj; //~ ERROR associated type `Proj` not found for `Family<Option<()>>`
let _: Family<std::path::PathBuf>::Proj = (); //~ ERROR associated type `Proj` not found for `Family<PathBuf>`
}
Loading
Loading