Auto merge of #114451 - matthiaskrgr:rollup-37qmv19, r=matthiaskrgr

Rollup of 5 pull requests

Successful merges:

 - #114022 (Perform OpaqueCast field projection on HIR, too.)
 - #114253 (Compute variances for lazy type aliases)
 - #114355 (resolve before canonicalization in new solver, ICE if unresolved)
 - #114427 (Handle non-utf8 rpaths (fix FIXME))
 - #114440 (bootstrap: config: fix version comparison bug)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-08-04 09:05:59 +00:00
commit 34ccd04859
40 changed files with 492 additions and 286 deletions

View File

@ -498,14 +498,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
/// Checks that the types internal to the `place` match up with
/// what would be expected.
#[instrument(level = "debug", skip(self, location), ret)]
fn sanitize_place(
&mut self,
place: &Place<'tcx>,
location: Location,
context: PlaceContext,
) -> PlaceTy<'tcx> {
debug!("sanitize_place: {:?}", place);
let mut place_ty = PlaceTy::from_ty(self.body().local_decls[place.local].ty);
for elem in place.projection.iter() {
@ -608,7 +607,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
}
}
#[instrument(skip(self), level = "debug")]
#[instrument(skip(self, location), ret, level = "debug")]
fn sanitize_projection(
&mut self,
base: PlaceTy<'tcx>,
@ -617,7 +616,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
location: Location,
context: PlaceContext,
) -> PlaceTy<'tcx> {
debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, place);
let tcx = self.tcx();
let base_ty = base.ty;
match pi {

View File

@ -1,6 +1,7 @@
use pathdiff::diff_paths;
use rustc_data_structures::fx::FxHashSet;
use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::{Path, PathBuf};
@ -12,7 +13,7 @@ pub struct RPathConfig<'a> {
pub linker_is_gnu: bool,
}
pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<String> {
pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<OsString> {
// No rpath on windows
if !config.has_rpath {
return Vec::new();
@ -21,36 +22,38 @@ pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<String> {
debug!("preparing the RPATH!");
let rpaths = get_rpaths(config);
let mut flags = rpaths_to_flags(&rpaths);
let mut flags = rpaths_to_flags(rpaths);
if config.linker_is_gnu {
// Use DT_RUNPATH instead of DT_RPATH if available
flags.push("-Wl,--enable-new-dtags".to_owned());
flags.push("-Wl,--enable-new-dtags".into());
// Set DF_ORIGIN for substitute $ORIGIN
flags.push("-Wl,-z,origin".to_owned());
flags.push("-Wl,-z,origin".into());
}
flags
}
fn rpaths_to_flags(rpaths: &[String]) -> Vec<String> {
fn rpaths_to_flags(rpaths: Vec<OsString>) -> Vec<OsString> {
let mut ret = Vec::with_capacity(rpaths.len()); // the minimum needed capacity
for rpath in rpaths {
if rpath.contains(',') {
if rpath.to_string_lossy().contains(',') {
ret.push("-Wl,-rpath".into());
ret.push("-Xlinker".into());
ret.push(rpath.clone());
ret.push(rpath);
} else {
ret.push(format!("-Wl,-rpath,{}", &(*rpath)));
let mut single_arg = OsString::from("-Wl,-rpath,");
single_arg.push(rpath);
ret.push(single_arg);
}
}
ret
}
fn get_rpaths(config: &mut RPathConfig<'_>) -> Vec<String> {
fn get_rpaths(config: &mut RPathConfig<'_>) -> Vec<OsString> {
debug!("output: {:?}", config.out_filename.display());
debug!("libs:");
for libpath in config.libs {
@ -64,18 +67,18 @@ fn get_rpaths(config: &mut RPathConfig<'_>) -> Vec<String> {
debug!("rpaths:");
for rpath in &rpaths {
debug!(" {}", rpath);
debug!(" {:?}", rpath);
}
// Remove duplicates
minimize_rpaths(&rpaths)
}
fn get_rpaths_relative_to_output(config: &mut RPathConfig<'_>) -> Vec<String> {
fn get_rpaths_relative_to_output(config: &mut RPathConfig<'_>) -> Vec<OsString> {
config.libs.iter().map(|a| get_rpath_relative_to_output(config, a)).collect()
}
fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> String {
fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> OsString {
// Mac doesn't appear to support $ORIGIN
let prefix = if config.is_like_osx { "@loader_path" } else { "$ORIGIN" };
@ -87,8 +90,11 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> Str
let output = fs::canonicalize(&output).unwrap_or(output);
let relative = path_relative_from(&lib, &output)
.unwrap_or_else(|| panic!("couldn't create relative path from {output:?} to {lib:?}"));
// FIXME (#9639): This needs to handle non-utf8 paths
format!("{}/{}", prefix, relative.to_str().expect("non-utf8 component in path"))
let mut rpath = OsString::from(prefix);
rpath.push("/");
rpath.push(relative);
rpath
}
// This routine is adapted from the *old* Path's `path_relative_from`
@ -99,7 +105,7 @@ fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
diff_paths(path, base)
}
fn minimize_rpaths(rpaths: &[String]) -> Vec<String> {
fn minimize_rpaths(rpaths: &[OsString]) -> Vec<OsString> {
let mut set = FxHashSet::default();
let mut minimized = Vec::new();
for rpath in rpaths {

View File

@ -1,32 +1,33 @@
use super::RPathConfig;
use super::{get_rpath_relative_to_output, minimize_rpaths, rpaths_to_flags};
use std::ffi::OsString;
use std::path::{Path, PathBuf};
#[test]
fn test_rpaths_to_flags() {
let flags = rpaths_to_flags(&["path1".to_string(), "path2".to_string()]);
let flags = rpaths_to_flags(vec!["path1".into(), "path2".into()]);
assert_eq!(flags, ["-Wl,-rpath,path1", "-Wl,-rpath,path2"]);
}
#[test]
fn test_minimize1() {
let res = minimize_rpaths(&["rpath1".to_string(), "rpath2".to_string(), "rpath1".to_string()]);
let res = minimize_rpaths(&["rpath1".into(), "rpath2".into(), "rpath1".into()]);
assert!(res == ["rpath1", "rpath2",]);
}
#[test]
fn test_minimize2() {
let res = minimize_rpaths(&[
"1a".to_string(),
"2".to_string(),
"2".to_string(),
"1a".to_string(),
"4a".to_string(),
"1a".to_string(),
"2".to_string(),
"3".to_string(),
"4a".to_string(),
"3".to_string(),
"1a".into(),
"2".into(),
"2".into(),
"1a".into(),
"4a".into(),
"1a".into(),
"2".into(),
"3".into(),
"4a".into(),
"3".into(),
]);
assert!(res == ["1a", "2", "4a", "3",]);
}
@ -58,15 +59,15 @@ fn test_rpath_relative() {
#[test]
fn test_xlinker() {
let args = rpaths_to_flags(&["a/normal/path".to_string(), "a,comma,path".to_string()]);
let args = rpaths_to_flags(vec!["a/normal/path".into(), "a,comma,path".into()]);
assert_eq!(
args,
vec![
"-Wl,-rpath,a/normal/path".to_string(),
"-Wl,-rpath".to_string(),
"-Xlinker".to_string(),
"a,comma,path".to_string()
OsString::from("-Wl,-rpath,a/normal/path"),
OsString::from("-Wl,-rpath"),
OsString::from("-Xlinker"),
OsString::from("a,comma,path")
]
);
}

View File

@ -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);

View File

@ -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 @@ 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
@ -127,6 +144,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
}
ty::Error(_) => {}
_ => {
span_bug!(
tcx.def_span(def_id),
@ -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);

View File

@ -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
@ -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);
}

View File

@ -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)
}
_ => {}
}
}

View File

@ -198,13 +198,14 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
}
/// Like `pat_ty`, but ignores implicit `&` patterns.
#[instrument(level = "debug", skip(self), ret)]
fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
let base_ty = self.node_ty(pat.hir_id)?;
debug!("pat_ty(pat={:?}) base_ty={:?}", pat, base_ty);
trace!(?base_ty);
// This code detects whether we are looking at a `ref x`,
// and if so, figures out what the type *being borrowed* is.
let ret_ty = match pat.kind {
match pat.kind {
PatKind::Binding(..) => {
let bm = *self
.typeck_results
@ -217,21 +218,18 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
// but what we want here is the type of the underlying value being borrowed.
// So peel off one-level, turning the &T into T.
match base_ty.builtin_deref(false) {
Some(t) => t.ty,
Some(t) => Ok(t.ty),
None => {
debug!("By-ref binding of non-derefable type {:?}", base_ty);
return Err(());
debug!("By-ref binding of non-derefable type");
Err(())
}
}
} else {
base_ty
Ok(base_ty)
}
}
_ => base_ty,
};
debug!("pat_ty(pat={:?}) ret_ty={:?}", pat, ret_ty);
Ok(ret_ty)
_ => Ok(base_ty),
}
}
pub(crate) fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> {
@ -299,13 +297,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
}
}
#[instrument(level = "debug", skip(self))]
#[instrument(level = "debug", skip(self), ret)]
pub(crate) fn cat_expr_unadjusted(
&self,
expr: &hir::Expr<'_>,
) -> McResult<PlaceWithHirId<'tcx>> {
debug!("cat_expr: id={} expr={:?}", expr.hir_id, expr);
let expr_ty = self.expr_ty(expr)?;
match expr.kind {
hir::ExprKind::Unary(hir::UnOp::Deref, ref e_base) => {
@ -319,7 +315,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
hir::ExprKind::Field(ref base, _) => {
let base = self.cat_expr(base)?;
debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.hir_id, expr, base);
debug!(?base);
let field_idx = self
.typeck_results
@ -389,7 +385,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
}
}
#[instrument(level = "debug", skip(self, span))]
#[instrument(level = "debug", skip(self, span), ret)]
pub(crate) fn cat_res(
&self,
hir_id: hir::HirId,
@ -430,6 +426,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
/// Note: the actual upvar access contains invisible derefs of closure
/// environment and upvar reference as appropriate. Only regionck cares
/// about these dereferences, so we let it compute them as needed.
#[instrument(level = "debug", skip(self), ret)]
fn cat_upvar(&self, hir_id: hir::HirId, var_id: hir::HirId) -> McResult<PlaceWithHirId<'tcx>> {
let closure_expr_def_id = self.body_owner;
@ -439,24 +436,20 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
};
let var_ty = self.node_ty(var_id)?;
let ret = PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new());
debug!("cat_upvar ret={:?}", ret);
Ok(ret)
Ok(PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new()))
}
#[instrument(level = "debug", skip(self), ret)]
pub(crate) fn cat_rvalue(
&self,
hir_id: hir::HirId,
span: Span,
expr_ty: Ty<'tcx>,
) -> PlaceWithHirId<'tcx> {
debug!("cat_rvalue hir_id={:?}, expr_ty={:?}, span={:?}", hir_id, expr_ty, span);
let ret = PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new());
debug!("cat_rvalue ret={:?}", ret);
ret
PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new())
}
#[instrument(level = "debug", skip(self, node), ret)]
pub(crate) fn cat_projection<N: HirNode>(
&self,
node: &N,
@ -464,16 +457,23 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
ty: Ty<'tcx>,
kind: ProjectionKind,
) -> PlaceWithHirId<'tcx> {
let place_ty = base_place.place.ty();
let mut projections = base_place.place.projections;
let node_ty = self.typeck_results.node_type(node.hir_id());
// Opaque types can't have field projections, but we can instead convert
// the current place in-place (heh) to the hidden type, and then apply all
// follow up projections on that.
if node_ty != place_ty && place_ty.has_opaque_types() {
projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty });
}
projections.push(Projection { kind, ty });
let ret = PlaceWithHirId::new(
PlaceWithHirId::new(
node.hir_id(),
base_place.place.base_ty,
base_place.place.base,
projections,
);
debug!("cat_field ret {:?}", ret);
ret
)
}
#[instrument(level = "debug", skip(self))]
@ -497,7 +497,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
self.cat_deref(expr, base)
}
#[instrument(level = "debug", skip(self, node))]
#[instrument(level = "debug", skip(self, node), ret)]
fn cat_deref(
&self,
node: &impl HirNode,
@ -514,14 +514,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
let mut projections = base_place.place.projections;
projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty });
let ret = PlaceWithHirId::new(
Ok(PlaceWithHirId::new(
node.hir_id(),
base_place.place.base_ty,
base_place.place.base,
projections,
);
debug!("cat_deref ret {:?}", ret);
Ok(ret)
))
}
pub(crate) fn cat_pattern<F>(
@ -603,6 +601,13 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
}
}
/// Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it
/// is being matched against.
///
/// In general, the way that this works is that we walk down the pattern,
/// constructing a `PlaceWithHirId` that represents the path that will be taken
/// to reach the value being matched.
#[instrument(skip(self, op), ret, level = "debug")]
fn cat_pattern_<F>(
&self,
mut place_with_id: PlaceWithHirId<'tcx>,
@ -612,15 +617,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
where
F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>),
{
// Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it
// is being matched against.
//
// In general, the way that this works is that we walk down the pattern,
// constructing a `PlaceWithHirId` that represents the path that will be taken
// to reach the value being matched.
debug!("cat_pattern(pat={:?}, place_with_id={:?})", pat, place_with_id);
// If (pattern) adjustments are active for this pattern, adjust the `PlaceWithHirId` correspondingly.
// `PlaceWithHirId`s are constructed differently from patterns. For example, in
//
@ -654,11 +650,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
// `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
// and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
for _ in 0..self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len()) {
debug!("cat_pattern: applying adjustment to place_with_id={:?}", place_with_id);
debug!("applying adjustment to place_with_id={:?}", place_with_id);
place_with_id = self.cat_deref(pat, place_with_id)?;
}
let place_with_id = place_with_id; // lose mutability
debug!("cat_pattern: applied adjustment derefs to get place_with_id={:?}", place_with_id);
debug!("applied adjustment derefs to get place_with_id={:?}", place_with_id);
// Invoke the callback, but only now, after the `place_with_id` has adjusted.
//

View File

@ -264,12 +264,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.demand_eqtype(span, closure_kind.to_ty(self.tcx), closure_kind_ty);
// If we have an origin, store it.
if let Some(origin) = origin {
let origin = if enable_precise_capture(span) {
(origin.0, origin.1)
} else {
(origin.0, Place { projections: vec![], ..origin.1 })
};
if let Some(mut origin) = origin {
if !enable_precise_capture(span) {
// Without precise captures, we just capture the base and ignore
// the projections.
origin.1.projections.clear()
}
self.typeck_results
.borrow_mut()
@ -294,10 +294,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Equate the type variables for the upvars with the actual types.
let final_upvar_tys = self.final_upvar_tys(closure_def_id);
debug!(
"analyze_closure: id={:?} args={:?} final_upvar_tys={:?}",
closure_hir_id, args, final_upvar_tys
);
debug!(?closure_hir_id, ?args, ?final_upvar_tys);
// Build a tuple (U0..Un) of the final upvar types U0..Un
// and unify the upvar tuple type in the closure with it:
@ -338,10 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let upvar_ty = captured_place.place.ty();
let capture = captured_place.info.capture_kind;
debug!(
"final_upvar_tys: place={:?} upvar_ty={:?} capture={:?}, mutability={:?}",
captured_place.place, upvar_ty, capture, captured_place.mutability,
);
debug!(?captured_place.place, ?upvar_ty, ?capture, ?captured_place.mutability);
apply_capture_kind_on_capture_ty(self.tcx, upvar_ty, capture, captured_place.region)
})
@ -679,6 +673,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match (p1.kind, p2.kind) {
// Paths are the same, continue to next loop.
(ProjectionKind::Deref, ProjectionKind::Deref) => {}
(ProjectionKind::OpaqueCast, ProjectionKind::OpaqueCast) => {}
(ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _))
if i1 == i2 => {}
@ -701,10 +696,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
l @ (ProjectionKind::Index
| ProjectionKind::Subslice
| ProjectionKind::Deref
| ProjectionKind::OpaqueCast
| ProjectionKind::Field(..)),
r @ (ProjectionKind::Index
| ProjectionKind::Subslice
| ProjectionKind::Deref
| ProjectionKind::OpaqueCast
| ProjectionKind::Field(..)),
) => bug!(
"ProjectionKinds Index or Subslice were unexpected: ({:?}, {:?})",
@ -1890,6 +1887,7 @@ fn restrict_capture_precision(
return (place, curr_mode);
}
ProjectionKind::Deref => {}
ProjectionKind::OpaqueCast => {}
ProjectionKind::Field(..) => {} // ignore
}
}
@ -1946,6 +1944,7 @@ fn construct_place_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String
ProjectionKind::Deref => String::from("Deref"),
ProjectionKind::Index => String::from("Index"),
ProjectionKind::Subslice => String::from("Subslice"),
ProjectionKind::OpaqueCast => String::from("OpaqueCast"),
};
if i != 0 {
projections_str.push(',');

View File

@ -562,15 +562,9 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
V: TypeFoldable<TyCtxt<'tcx>>,
{
let needs_canonical_flags = if canonicalize_region_mode.any() {
TypeFlags::HAS_INFER |
TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS`
TypeFlags::HAS_TY_PLACEHOLDER |
TypeFlags::HAS_CT_PLACEHOLDER
TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_FREE_REGIONS
} else {
TypeFlags::HAS_INFER
| TypeFlags::HAS_RE_PLACEHOLDER
| TypeFlags::HAS_TY_PLACEHOLDER
| TypeFlags::HAS_CT_PLACEHOLDER
TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER
};
// Fast path: nothing that needs to be canonicalized.

View File

@ -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};
@ -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 @@ 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);
}

View File

@ -36,6 +36,10 @@ pub enum ProjectionKind {
/// A subslice covering a range of values like `B[x..y]`.
Subslice,
/// A conversion from an opaque type to its hidden type so we can
/// do further projections on it.
OpaqueCast,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]

View File

@ -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" }

View File

@ -147,7 +147,7 @@ impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> {
}
/// Additional constraints returned on success.
#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)]
#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default, TypeVisitable, TypeFoldable)]
pub struct ExternalConstraintsData<'tcx> {
// FIXME: implement this.
pub region_constraints: QueryRegionConstraints<'tcx>,

View File

@ -174,6 +174,8 @@ impl<'tcx> CapturedPlace<'tcx> {
// Ignore derefs for now, as they are likely caused by
// autoderefs that don't appear in the original code.
HirProjectionKind::Deref => {}
// Just change the type to the hidden type, so we can actually project.
HirProjectionKind::OpaqueCast => {}
proj => bug!("Unexpected projection {:?} in captured place", proj),
}
ty = proj.ty;

View File

@ -88,14 +88,10 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
self.has_type_flags(TypeFlags::HAS_INFER)
}
fn has_placeholders(&self) -> bool {
self.has_type_flags(
TypeFlags::HAS_RE_PLACEHOLDER
| TypeFlags::HAS_TY_PLACEHOLDER
| TypeFlags::HAS_CT_PLACEHOLDER,
)
self.has_type_flags(TypeFlags::HAS_PLACEHOLDER)
}
fn has_non_region_placeholders(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER)
self.has_type_flags(TypeFlags::HAS_PLACEHOLDER - TypeFlags::HAS_RE_PLACEHOLDER)
}
fn has_param(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_PARAM)

View File

@ -236,6 +236,9 @@ fn strip_prefix<'a, 'tcx>(
}
assert_matches!(iter.next(), Some(ProjectionElem::Field(..)));
}
HirProjectionKind::OpaqueCast => {
assert_matches!(iter.next(), Some(ProjectionElem::OpaqueCast(..)));
}
HirProjectionKind::Index | HirProjectionKind::Subslice => {
bug!("unexpected projection kind: {:?}", projection);
}

View File

@ -1072,6 +1072,9 @@ impl<'tcx> Cx<'tcx> {
variant_index,
name: field,
},
HirProjectionKind::OpaqueCast => {
ExprKind::Use { source: self.thir.exprs.push(captured_place_expr) }
}
HirProjectionKind::Index | HirProjectionKind::Subslice => {
// We don't capture these projections, so we can ignore them here
continue;

View File

@ -207,23 +207,18 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
t
}
fn fold_region(&mut self, mut r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match self.canonicalize_mode {
CanonicalizeMode::Input => {
// Don't resolve infer vars in input, since it affects
// caching and may cause trait selection bugs which rely
// on regions to be equal.
}
CanonicalizeMode::Response { .. } => {
if let ty::ReVar(vid) = *r {
r = self
.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
.opportunistic_resolve_var(self.infcx.tcx, vid);
}
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
if let ty::ReVar(vid) = *r {
let resolved_region = self
.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
.opportunistic_resolve_var(self.infcx.tcx, vid);
assert_eq!(
r, resolved_region,
"region var should have been resolved, {r} -> {resolved_region}"
);
}
let kind = match *r {
@ -278,38 +273,22 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
ty::Region::new_late_bound(self.interner(), self.binder_index, br)
}
fn fold_ty(&mut self, mut t: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
let kind = match *t.kind() {
ty::Infer(ty::TyVar(mut vid)) => {
// We need to canonicalize the *root* of our ty var.
// This is so that our canonical response correctly reflects
// any equated inference vars correctly!
let root_vid = self.infcx.root_var(vid);
if root_vid != vid {
t = Ty::new_var(self.infcx.tcx, root_vid);
vid = root_vid;
}
match self.infcx.probe_ty_var(vid) {
Ok(t) => return self.fold_ty(t),
Err(ui) => CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
}
ty::Infer(ty::TyVar(vid)) => {
assert_eq!(self.infcx.root_var(vid), vid, "ty vid should have been resolved");
let Err(ui) = self.infcx.probe_ty_var(vid) else {
bug!("ty var should have been resolved: {t}");
};
CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
}
ty::Infer(ty::IntVar(vid)) => {
let nt = self.infcx.opportunistic_resolve_int_var(vid);
if nt != t {
return self.fold_ty(nt);
} else {
CanonicalVarKind::Ty(CanonicalTyVarKind::Int)
}
assert_eq!(self.infcx.opportunistic_resolve_int_var(vid), t);
CanonicalVarKind::Ty(CanonicalTyVarKind::Int)
}
ty::Infer(ty::FloatVar(vid)) => {
let nt = self.infcx.opportunistic_resolve_float_var(vid);
if nt != t {
return self.fold_ty(nt);
} else {
CanonicalVarKind::Ty(CanonicalTyVarKind::Float)
}
assert_eq!(self.infcx.opportunistic_resolve_float_var(vid), t);
CanonicalVarKind::Ty(CanonicalTyVarKind::Float)
}
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("fresh var during canonicalization: {t:?}")
@ -372,22 +351,19 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
Ty::new_bound(self.infcx.tcx, self.binder_index, bt)
}
fn fold_const(&mut self, mut c: ty::Const<'tcx>) -> ty::Const<'tcx> {
fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
let kind = match c.kind() {
ty::ConstKind::Infer(ty::InferConst::Var(mut vid)) => {
// We need to canonicalize the *root* of our const var.
// This is so that our canonical response correctly reflects
// any equated inference vars correctly!
let root_vid = self.infcx.root_const_var(vid);
if root_vid != vid {
c = ty::Const::new_var(self.infcx.tcx, root_vid, c.ty());
vid = root_vid;
}
match self.infcx.probe_const_var(vid) {
Ok(c) => return self.fold_const(c),
Err(universe) => CanonicalVarKind::Const(universe, c.ty()),
}
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
assert_eq!(
self.infcx.root_const_var(vid),
vid,
"const var should have been resolved"
);
let Err(ui) = self.infcx.probe_const_var(vid) else {
bug!("const var should have been resolved");
};
// FIXME: we should fold this ty eventually
CanonicalVarKind::Const(ui, c.ty())
}
ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => {
bug!("fresh var during canonicalization: {c:?}")

View File

@ -16,11 +16,15 @@ use rustc_index::IndexVec;
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
use rustc_infer::infer::canonical::CanonicalVarValues;
use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
use rustc_infer::infer::InferCtxt;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::solve::{
ExternalConstraints, ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput,
ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput,
};
use rustc_middle::ty::{
self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
TypeVisitableExt,
};
use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable};
use rustc_span::DUMMY_SP;
use std::iter;
use std::ops::Deref;
@ -32,6 +36,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
&self,
goal: Goal<'tcx, T>,
) -> (Vec<ty::GenericArg<'tcx>>, CanonicalInput<'tcx, T>) {
let opaque_types = self.infcx.clone_opaque_types_for_query_response();
let (goal, opaque_types) =
(goal, opaque_types).fold_with(&mut EagerResolver { infcx: self.infcx });
let mut orig_values = Default::default();
let canonical_goal = Canonicalizer::canonicalize(
self.infcx,
@ -40,11 +48,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
QueryInput {
goal,
anchor: self.infcx.defining_use_anchor,
predefined_opaques_in_body: self.tcx().mk_predefined_opaques_in_body(
PredefinedOpaquesData {
opaque_types: self.infcx.clone_opaque_types_for_query_response(),
},
),
predefined_opaques_in_body: self
.tcx()
.mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }),
},
);
(orig_values, canonical_goal)
@ -70,34 +76,43 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
);
let certainty = certainty.unify_with(goals_certainty);
if let Certainty::OVERFLOW = certainty {
// If we have overflow, it's probable that we're substituting a type
// into itself infinitely and any partial substitutions in the query
// response are probably not useful anyways, so just return an empty
// query response.
//
// This may prevent us from potentially useful inference, e.g.
// 2 candidates, one ambiguous and one overflow, which both
// have the same inference constraints.
//
// Changing this to retain some constraints in the future
// won't be a breaking change, so this is good enough for now.
return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow));
}
let response = match certainty {
Certainty::Yes | Certainty::Maybe(MaybeCause::Ambiguity) => {
let external_constraints = self.compute_external_query_constraints()?;
Response { var_values: self.var_values, external_constraints, certainty }
}
Certainty::Maybe(MaybeCause::Overflow) => {
// If we have overflow, it's probable that we're substituting a type
// into itself infinitely and any partial substitutions in the query
// response are probably not useful anyways, so just return an empty
// query response.
//
// This may prevent us from potentially useful inference, e.g.
// 2 candidates, one ambiguous and one overflow, which both
// have the same inference constraints.
//
// Changing this to retain some constraints in the future
// won't be a breaking change, so this is good enough for now.
return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow));
}
};
let var_values = self.var_values;
let external_constraints = self.compute_external_query_constraints()?;
let (var_values, mut external_constraints) =
(var_values, external_constraints).fold_with(&mut EagerResolver { infcx: self.infcx });
// Remove any trivial region constraints once we've resolved regions
external_constraints
.region_constraints
.outlives
.retain(|(outlives, _)| outlives.0.as_region().map_or(true, |re| re != outlives.1));
let canonical = Canonicalizer::canonicalize(
self.infcx,
CanonicalizeMode::Response { max_input_universe: self.max_input_universe },
&mut Default::default(),
response,
Response {
var_values,
certainty,
external_constraints: self.tcx().mk_external_constraints(external_constraints),
},
);
Ok(canonical)
}
@ -143,7 +158,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
/// further constrained by inference, that will be passed back in the var
/// values.
#[instrument(level = "debug", skip(self), ret)]
fn compute_external_query_constraints(&self) -> Result<ExternalConstraints<'tcx>, NoSolution> {
fn compute_external_query_constraints(
&self,
) -> Result<ExternalConstraintsData<'tcx>, NoSolution> {
// We only check for leaks from universes which were entered inside
// of the query.
self.infcx.leak_check(self.max_input_universe, None).map_err(|e| {
@ -173,9 +190,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a)
});
Ok(self
.tcx()
.mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types }))
Ok(ExternalConstraintsData { region_constraints, opaque_types })
}
/// After calling a canonical query, we apply the constraints returned
@ -333,3 +348,65 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
Ok(())
}
}
/// Resolves ty, region, and const vars to their inferred values or their root vars.
struct EagerResolver<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
}
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EagerResolver<'_, 'tcx> {
fn interner(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
match *t.kind() {
ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(vid) {
Ok(t) => t.fold_with(self),
Err(_) => Ty::new_var(self.infcx.tcx, self.infcx.root_var(vid)),
},
ty::Infer(ty::IntVar(vid)) => self.infcx.opportunistic_resolve_int_var(vid),
ty::Infer(ty::FloatVar(vid)) => self.infcx.opportunistic_resolve_float_var(vid),
_ => {
if t.has_infer() {
t.super_fold_with(self)
} else {
t
}
}
}
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
ty::ReVar(vid) => self
.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
.opportunistic_resolve_var(self.infcx.tcx, vid),
_ => r,
}
}
fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
match c.kind() {
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
// FIXME: we need to fold the ty too, I think.
match self.infcx.probe_const_var(vid) {
Ok(c) => c.fold_with(self),
Err(_) => {
ty::Const::new_var(self.infcx.tcx, self.infcx.root_const_var(vid), c.ty())
}
}
}
_ => {
if c.has_infer() {
c.super_fold_with(self)
} else {
c
}
}
}
}
}

View File

@ -216,6 +216,11 @@ bitflags! {
/// Does this have `ConstKind::Placeholder`?
const HAS_CT_PLACEHOLDER = 1 << 8;
/// Does this have placeholders?
const HAS_PLACEHOLDER = TypeFlags::HAS_TY_PLACEHOLDER.bits
| TypeFlags::HAS_RE_PLACEHOLDER.bits
| TypeFlags::HAS_CT_PLACEHOLDER.bits;
/// `true` if there are "names" of regions and so forth
/// that are local to a particular fn/inferctxt
const HAS_FREE_LOCAL_REGIONS = 1 << 9;

View File

@ -2004,7 +2004,8 @@ impl Config {
.unwrap();
if !(source_version == rustc_version
|| (source_version.major == rustc_version.major
&& source_version.minor == rustc_version.minor + 1))
&& (source_version.minor == rustc_version.minor
|| source_version.minor == rustc_version.minor + 1)))
{
let prev_version = format!("{}.{}.x", source_version.major, source_version.minor - 1);
eprintln!(

View File

@ -1011,6 +1011,8 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
},
// note: unable to trigger `Subslice` kind in tests
ProjectionKind::Subslice => (),
// Doesn't have surface syntax. Only occurs in patterns.
ProjectionKind::OpaqueCast => (),
ProjectionKind::Deref => {
// Explicit derefs are typically handled later on, but
// some items do not need explicit deref, such as array accesses,

View File

@ -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;

View File

@ -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> {

View File

@ -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 ());
@ -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);

View File

@ -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() {}

View File

@ -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

View File

@ -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 {
@ -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`

View File

@ -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)
| ^^------^

View File

@ -1,16 +0,0 @@
error[E0220]: associated type `Proj` not found for `Family<Option<()>>` in the current scope
--> $DIR/not-found-self-type-differs.rs:17:34
|
LL | struct Family<T>(T);
| ---------------- associated item `Proj` not found for this struct
...
LL | type Alias = Family<Option<()>>::Proj;
| ^^^^ associated item not found in `Family<Option<()>>`
|
= note: the associated type was found for
- `Family<()>`
- `Family<Result<T, ()>>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0220`.

View File

@ -1,16 +0,0 @@
error[E0220]: associated type `Proj` not found for `Family<PathBuf>` in the current scope
--> $DIR/not-found-self-type-differs.rs:21:40
|
LL | struct Family<T>(T);
| ---------------- associated item `Proj` not found for this struct
...
LL | let _: Family<std::path::PathBuf>::Proj = ();
| ^^^^ associated item not found in `Family<PathBuf>`
|
= note: the associated type was found for
- `Family<()>`
- `Family<Result<T, ()>>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0220`.

View File

@ -1,5 +1,3 @@
// revisions: local alias
#![feature(inherent_associated_types)]
#![allow(incomplete_features)]
@ -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>`
}

View File

@ -0,0 +1,29 @@
error[E0220]: associated type `Proj` not found for `Family<Option<()>>` in the current scope
--> $DIR/not-found-self-type-differs.rs:15:32
|
LL | struct Family<T>(T);
| ---------------- associated item `Proj` not found for this struct
...
LL | let _: Family<Option<()>>::Proj;
| ^^^^ associated item not found in `Family<Option<()>>`
|
= note: the associated type was found for
- `Family<()>`
- `Family<Result<T, ()>>`
error[E0220]: associated type `Proj` not found for `Family<PathBuf>` in the current scope
--> $DIR/not-found-self-type-differs.rs:16:40
|
LL | struct Family<T>(T);
| ---------------- associated item `Proj` not found for this struct
...
LL | let _: Family<std::path::PathBuf>::Proj = ();
| ^^^^ associated item not found in `Family<PathBuf>`
|
= note: the associated type was found for
- `Family<()>`
- `Family<Result<T, ()>>`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0220`.

View File

@ -17,7 +17,7 @@ impl<T, S> Subj<(T, S)> {
}
fn main() {
type A = S<()>::P;
let _: S<()>::P;
let _: Subj<(i32, i32)>::Un = 0i32; //~ ERROR mismatched types
}

View File

@ -15,8 +15,7 @@ impl<T> S<(T,)> {
fn main() {
// Regression test for issue #104240.
type A = S<()>::P;
let _: A = ();
let _: S<()>::P = ();
// Regression test for issue #107468.
let _: S<(i32,)>::Un = 0i32;

View File

@ -1,4 +1,5 @@
// check-pass
// FIXME(inherent_associated_types): This should be `check-pass`
// known-bug: #108491
// compile-flags: --crate-type=lib
#![feature(inherent_associated_types)]
@ -17,7 +18,6 @@
pub type Alias<T: Bound> = (Source<T>::Assoc,);
pub struct Source<T>(T);
pub trait Bound {}

View File

@ -0,0 +1,55 @@
error[E0391]: cycle detected when expanding type alias `Alias`
--> $DIR/type-alias-bounds-are-enforced.rs:19:1
|
LL | pub type Alias<T: Bound> = (Source<T>::Assoc,);
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
note: ...which requires computing the variances of `Source`...
--> $DIR/type-alias-bounds-are-enforced.rs:21:1
|
LL | pub struct Source<T>(T);
| ^^^^^^^^^^^^^^^^^^^^
= note: ...which requires computing the variances for items in this crate...
= note: ...which again requires expanding type alias `Alias`, completing the cycle
note: cycle used when collecting item types in top-level module
--> $DIR/type-alias-bounds-are-enforced.rs:5:1
|
LL | / #![feature(inherent_associated_types)]
LL | | #![allow(incomplete_features)]
LL | |
LL | | // Bounds on the self type play a major role in the resolution of inherent associated types (*).
... |
LL | | pub type Assoc = ();
LL | | }
| |_^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
error[E0391]: cycle detected when expanding type alias `Alias`
--> $DIR/type-alias-bounds-are-enforced.rs:19:1
|
LL | pub type Alias<T: Bound> = (Source<T>::Assoc,);
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
note: ...which requires computing the variances of `Source`...
--> $DIR/type-alias-bounds-are-enforced.rs:21:1
|
LL | pub struct Source<T>(T);
| ^^^^^^^^^^^^^^^^^^^^
= note: ...which requires computing the variances for items in this crate...
= note: ...which again requires expanding type alias `Alias`, completing the cycle
note: cycle used when collecting item types in top-level module
--> $DIR/type-alias-bounds-are-enforced.rs:5:1
|
LL | / #![feature(inherent_associated_types)]
LL | | #![allow(incomplete_features)]
LL | |
LL | | // Bounds on the self type play a major role in the resolution of inherent associated types (*).
... |
LL | | pub type Assoc = ();
LL | | }
| |_^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0391`.

View 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() {}

View File

@ -1,5 +1,7 @@
#![feature(type_alias_impl_trait)]
// check-pass
// revisions: default edition2021
//[edition2021] compile-flags: --edition 2021
fn main() {
type T = impl Copy;