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

Add some comments, add can_define_opaque_ty check to try_normalize_ty_recur #118915

Merged
merged 3 commits into from
Jan 11, 2024
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
4 changes: 2 additions & 2 deletions compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
let mut failed = false;

let elaborated_args = std::iter::zip(*args, &generics.params).map(|(arg, param)| {
if let Some(ty::Dynamic(obj, _, ty::DynKind::Dyn)) = arg.as_type().map(Ty::kind) {
if let Some(ty::Dynamic(obj, _, ty::Dyn)) = arg.as_type().map(Ty::kind) {
let default = tcx.object_lifetime_default(param.def_id);

let re_static = tcx.lifetimes.re_static;
Expand All @@ -339,7 +339,7 @@ impl<'tcx> BorrowExplanation<'tcx> {

has_dyn = true;

Ty::new_dynamic(tcx, obj, implied_region, ty::DynKind::Dyn).into()
Ty::new_dynamic(tcx, obj, implied_region, ty::Dyn).into()
} else {
arg
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2348,11 +2348,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
GenericKind::Param(ref p) => format!("the parameter type `{p}`"),
GenericKind::Placeholder(ref p) => format!("the placeholder type `{p:?}`"),
GenericKind::Alias(ref p) => match p.kind(self.tcx) {
ty::AliasKind::Projection | ty::AliasKind::Inherent => {
ty::Projection | ty::Inherent => {
format!("the associated type `{p}`")
}
ty::AliasKind::Weak => format!("the type alias `{p}`"),
ty::AliasKind::Opaque => format!("the opaque type `{p}`"),
ty::Weak => format!("the type alias `{p}`"),
ty::Opaque => format!("the opaque type `{p}`"),
},
};

Expand Down
9 changes: 4 additions & 5 deletions compiler/rustc_infer/src/infer/relate/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
));
} else {
match a_ty.kind() {
&ty::Alias(ty::AliasKind::Projection, data) => {
&ty::Alias(ty::Projection, data) => {
// FIXME: This does not handle subtyping correctly, we could
// instead create a new inference variable for `a_ty`, emitting
// `Projection(a_ty, a_infer)` and `a_infer <: b_ty`.
Expand All @@ -523,10 +523,9 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
))
}
// The old solver only accepts projection predicates for associated types.
ty::Alias(
ty::AliasKind::Inherent | ty::AliasKind::Weak | ty::AliasKind::Opaque,
_,
) => return Err(TypeError::CyclicTy(a_ty)),
ty::Alias(ty::Inherent | ty::Weak | ty::Opaque, _) => {
return Err(TypeError::CyclicTy(a_ty));
}
_ => bug!("generalizated `{a_ty:?} to infer, not an alias"),
}
}
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_lint/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ use rustc_span::{Span, Symbol};
use rustc_target::abi::{Abi, Size, WrappingRange};
use rustc_target::abi::{Integer, TagEncoding, Variants};
use rustc_target::spec::abi::Abi as SpecAbi;
use rustc_type_ir::DynKind;

use std::iter;
use std::ops::ControlFlow;
Expand Down Expand Up @@ -675,7 +674,7 @@ fn lint_wide_pointer<'tcx>(
}
match ty.kind() {
ty::RawPtr(TypeAndMut { mutbl: _, ty }) => (!ty.is_sized(cx.tcx, cx.param_env))
.then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, DynKind::Dyn)))),
.then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn)))),
_ => None,
}
};
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1225,7 +1225,7 @@ impl<'tcx> AliasTy<'tcx> {

/// Whether this alias type is an opaque.
pub fn is_opaque(self, tcx: TyCtxt<'tcx>) -> bool {
matches!(self.opt_kind(tcx), Some(ty::AliasKind::Opaque))
matches!(self.opt_kind(tcx), Some(ty::Opaque))
}

/// FIXME: rename `AliasTy` to `AliasTerm` and always handle
Expand Down Expand Up @@ -2745,7 +2745,7 @@ impl<'tcx> Ty<'tcx> {
// Extern types have metadata = ().
| ty::Foreign(..)
// `dyn*` has no metadata
| ty::Dynamic(_, _, DynKind::DynStar)
| ty::Dynamic(_, _, ty::DynStar)
// If returned by `struct_tail_without_normalization` this is a unit struct
// without any fields, or not a struct, and therefore is Sized.
| ty::Adt(..)
Expand All @@ -2754,7 +2754,7 @@ impl<'tcx> Ty<'tcx> {
| ty::Tuple(..) => (tcx.types.unit, false),

ty::Str | ty::Slice(_) => (tcx.types.usize, false),
ty::Dynamic(_, _, DynKind::Dyn) => {
ty::Dynamic(_, _, ty::Dyn) => {
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]), false)
},
Expand Down
14 changes: 6 additions & 8 deletions compiler/rustc_smir/src/rustc_smir/convert/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,11 @@ use crate::rustc_smir::{alloc, Stable, Tables};
impl<'tcx> Stable<'tcx> for ty::AliasKind {
type T = stable_mir::ty::AliasKind;
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
use rustc_middle::ty::AliasKind::*;
match self {
Projection => stable_mir::ty::AliasKind::Projection,
Inherent => stable_mir::ty::AliasKind::Inherent,
Opaque => stable_mir::ty::AliasKind::Opaque,
Weak => stable_mir::ty::AliasKind::Weak,
ty::Projection => stable_mir::ty::AliasKind::Projection,
ty::Inherent => stable_mir::ty::AliasKind::Inherent,
ty::Opaque => stable_mir::ty::AliasKind::Opaque,
ty::Weak => stable_mir::ty::AliasKind::Weak,
}
}
}
Expand All @@ -34,10 +33,9 @@ impl<'tcx> Stable<'tcx> for ty::DynKind {
type T = stable_mir::ty::DynKind;

fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
use rustc_middle::ty::DynKind;
match self {
DynKind::Dyn => stable_mir::ty::DynKind::Dyn,
DynKind::DynStar => stable_mir::ty::DynKind::DynStar,
ty::Dyn => stable_mir::ty::DynKind::Dyn,
ty::DynStar => stable_mir::ty::DynKind::DynStar,
}
}
}
Expand Down
35 changes: 26 additions & 9 deletions compiler/rustc_trait_selection/src/solve/alias_relate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,29 @@
//! Doing this via a separate goal is called "deferred alias relation" and part
//! of our more general approach to "lazy normalization".
//!
//! This goal, e.g. `A alias-relate B`, may be satisfied by one of three branches:
//! * normalizes-to: If `A` is a projection, we can prove the equivalent
//! projection predicate with B as the right-hand side of the projection.
//! This goal is computed in both directions, if both are aliases.
//! * subst-relate: Equate `A` and `B` by their substs, if they're both
//! aliases with the same def-id.
//! * bidirectional-normalizes-to: If `A` and `B` are both projections, and both
//! may apply, then we can compute the "intersection" of both normalizes-to by
//! performing them together. This is used specifically to resolve ambiguities.
//! This is done by first normalizing both sides of the goal, ending up in
//! either a concrete type, rigid projection, opaque, or an infer variable.
//! These are related further according to the rules below:
//!
//! (1.) If we end up with a rigid projection and a rigid projection, then we
//! relate those projections structurally.
//!
//! (2.) If we end up with a rigid projection and an alias, then the opaque will
//! have its hidden type defined to be that rigid projection.
//!
//! (3.) If we end up with an opaque and an opaque, then we assemble two
//! candidates, one defining the LHS to be the hidden type of the RHS, and vice
//! versa.
//!
//! (4.) If we end up with an infer var and an opaque or rigid projection, then
//! we assign the alias to the infer var.
//!
//! (5.) If we end up with an opaque and a rigid (non-projection) type, then we
//! define the hidden type of the opaque to be the rigid type.
//!
//! (6.) Otherwise, if we end with two rigid (non-projection) or infer types,
//! relate them structurally.

use super::{EvalCtxt, GoalSource};
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::query::NoSolution;
Expand Down Expand Up @@ -50,6 +64,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
self.relate(param_env, lhs, variance, rhs)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} else if alias.is_opaque(tcx) {
// FIXME: This doesn't account for variance.
self.define_opaque(param_env, alias, rhs)
} else {
Err(NoSolution)
Expand All @@ -60,6 +75,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
self.relate(param_env, lhs, variance, rhs)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} else if alias.is_opaque(tcx) {
// FIXME: This doesn't account for variance.
self.define_opaque(param_env, alias, lhs)
} else {
Err(NoSolution)
Expand All @@ -72,6 +88,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
}

// FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var.
/// Normalize the `term` to equate it later. This does not define opaque types.
#[instrument(level = "debug", skip(self, param_env), ret)]
fn try_normalize_term(
Expand Down
33 changes: 20 additions & 13 deletions compiler/rustc_trait_selection/src/solve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use rustc_middle::traits::solve::{
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack,
QueryResult, Response,
};
use rustc_middle::traits::Reveal;
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, UniverseIndex};
use rustc_middle::ty::{
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
Expand Down Expand Up @@ -316,19 +317,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
return Some(ty);
};

// We do no always define opaque types eagerly to allow non-defining uses in the defining scope.
if let (DefineOpaqueTypes::No, ty::AliasKind::Opaque) = (define_opaque_types, kind) {
if let Some(def_id) = alias.def_id.as_local() {
if self
.unify_existing_opaque_tys(
param_env,
OpaqueTypeKey { def_id, args: alias.args },
self.next_ty_infer(),
)
.is_empty()
{
return Some(ty);
}
// We do no always define opaque types eagerly to allow non-defining uses
// in the defining scope. However, if we can unify this opaque to an existing
// opaque, then we should attempt to eagerly reveal the opaque, and we fall
// through.
if let DefineOpaqueTypes::No = define_opaque_types
&& let Reveal::UserFacing = param_env.reveal()
&& let ty::Opaque = kind
&& let Some(def_id) = alias.def_id.as_local()
&& self.can_define_opaque_ty(def_id)
{
if self
.unify_existing_opaque_tys(
param_env,
OpaqueTypeKey { def_id, args: alias.args },
self.next_ty_infer(),
)
.is_empty()
{
return Some(ty);
}
}

Expand Down