mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-19 18:34:08 +00:00
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:
commit
34ccd04859
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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")
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@ -245,13 +245,14 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
}
|
||||
// `ForeignItem`s are handled separately.
|
||||
hir::ItemKind::ForeignMod { .. } => {}
|
||||
hir::ItemKind::TyAlias(hir_ty, ..) => {
|
||||
hir::ItemKind::TyAlias(hir_ty, ast_generics) => {
|
||||
if tcx.features().lazy_type_alias
|
||||
|| tcx.type_of(item.owner_id).skip_binder().has_opaque_types()
|
||||
{
|
||||
// Bounds of lazy type aliases and of eager ones that contain opaque types are respected.
|
||||
// E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`.
|
||||
check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow);
|
||||
check_variances_for_type_defn(tcx, item, ast_generics);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@ -1700,10 +1701,27 @@ fn check_variances_for_type_defn<'tcx>(
|
||||
hir_generics: &hir::Generics<'_>,
|
||||
) {
|
||||
let identity_args = ty::GenericArgs::identity_for_item(tcx, item.owner_id);
|
||||
for field in tcx.adt_def(item.owner_id).all_fields() {
|
||||
if field.ty(tcx, identity_args).references_error() {
|
||||
return;
|
||||
|
||||
match item.kind {
|
||||
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
|
||||
for field in tcx.adt_def(item.owner_id).all_fields() {
|
||||
if field.ty(tcx, identity_args).references_error() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
ItemKind::TyAlias(..) => {
|
||||
let ty = tcx.type_of(item.owner_id).instantiate_identity();
|
||||
|
||||
if tcx.features().lazy_type_alias || ty.has_opaque_types() {
|
||||
if ty.references_error() {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
bug!();
|
||||
}
|
||||
}
|
||||
_ => bug!(),
|
||||
}
|
||||
|
||||
let ty_predicates = tcx.predicates_of(item.owner_id);
|
||||
|
@ -6,7 +6,7 @@
|
||||
use hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
|
||||
|
||||
use super::terms::VarianceTerm::*;
|
||||
@ -78,6 +78,12 @@ pub fn add_constraints_from_crate<'a, 'tcx>(
|
||||
}
|
||||
}
|
||||
DefKind::Fn | DefKind::AssocFn => constraint_cx.build_constraints_for_item(def_id),
|
||||
DefKind::TyAlias
|
||||
if tcx.features().lazy_type_alias
|
||||
|| tcx.type_of(def_id).instantiate_identity().has_opaque_types() =>
|
||||
{
|
||||
constraint_cx.build_constraints_for_item(def_id)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -101,7 +107,18 @@ 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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
//
|
||||
|
@ -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(',');
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)]
|
||||
|
@ -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" }
|
||||
|
@ -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>,
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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:?}")
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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!(
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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> {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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`
|
||||
|
@ -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)
|
||||
| ^^------^
|
||||
|
@ -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`.
|
@ -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`.
|
@ -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>`
|
||||
}
|
||||
|
@ -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`.
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 {}
|
||||
|
||||
|
@ -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`.
|
38
tests/ui/lazy-type-alias/variance.rs
Normal file
38
tests/ui/lazy-type-alias/variance.rs
Normal file
@ -0,0 +1,38 @@
|
||||
// This is a regression test for issue #114221.
|
||||
// Check that we compute variances for lazy type aliases.
|
||||
|
||||
// check-pass
|
||||
|
||||
#![feature(lazy_type_alias)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// [+] `A` is covariant over `'a`.
|
||||
struct A<'a>(Co<'a>);
|
||||
|
||||
// [+] `Co` is covariant over `'a`.
|
||||
type Co<'a> = &'a ();
|
||||
|
||||
fn co<'a>(x: A<'static>) {
|
||||
let _: A<'a> = x;
|
||||
}
|
||||
|
||||
// [-] `B` is contravariant over `'a`.
|
||||
struct B<'a>(Contra<'a>);
|
||||
|
||||
// [-] `Contra` is contravariant over `'a`.
|
||||
type Contra<'a> = fn(&'a ());
|
||||
|
||||
fn contra<'a>(x: B<'a>) {
|
||||
let _: B<'static> = x;
|
||||
}
|
||||
|
||||
struct C<T, U>(CoContra<T, U>);
|
||||
|
||||
// [+, -] `CoContra` is covariant over `T` and contravariant over `U`.
|
||||
type CoContra<T, U> = Option<(T, fn(U))>;
|
||||
|
||||
fn co_contra<'a>(x: C<&'static (), &'a ()>) -> C<&'a (), &'static ()> {
|
||||
x
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user