Skip to content

Commit 62953e6

Browse files
committed
Introduce const-qualified paths
1 parent 5e2e50a commit 62953e6

29 files changed

+570
-118
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,6 +1574,16 @@ impl GenBlockKind {
15741574
pub struct QSelf {
15751575
pub ty: P<Ty>,
15761576

1577+
/// The constness of the trait (under feature `const_trait_impl`).
1578+
///
1579+
/// * `<Type as Trait>::AssocTy`: `BoundConstness::Never`
1580+
/// * `<Type as const Trait>::AssocTy`: `BoundConstness::Always`
1581+
/// * `<Type as ~const Trait>::AssocTy`: `BoundConstness::Maybe`
1582+
// FIXME(effects): This is the most convenient place to put this information but
1583+
// it doesn't make much sense from a conceptual viewpoint since it doesn't have
1584+
// much to do with the self type.
1585+
pub constness: BoundConstness,
1586+
15771587
/// The span of `a::b::Trait` in a path like `<Vec<T> as
15781588
/// a::b::Trait>::AssociatedItem`; in the case where `position ==
15791589
/// 0`, this is an empty span.

compiler/rustc_ast/src/mut_visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ pub fn noop_visit_path<T: MutVisitor>(Path { segments, span, tokens }: &mut Path
559559

560560
pub fn noop_visit_qself<T: MutVisitor>(qself: &mut Option<P<QSelf>>, vis: &mut T) {
561561
visit_opt(qself, |qself| {
562-
let QSelf { ty, path_span, position: _ } = &mut **qself;
562+
let QSelf { ty, constness: _, path_span, position: _ } = &mut **qself;
563563
vis.visit_ty(ty);
564564
vis.visit_span(path_span);
565565
})

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -200,36 +200,35 @@ impl<'hir> LoweringContext<'_, 'hir> {
200200
hir::ItemKind::Const(ty, generics, body_id)
201201
}
202202
ItemKind::Fn(box Fn {
203-
sig: FnSig { decl, header, span: fn_sig_span },
203+
sig: FnSig { decl: ast_decl, header, span: fn_sig_span },
204204
generics,
205205
body,
206206
..
207207
}) => {
208208
self.with_new_scopes(ident.span, |this| {
209-
// Note: we don't need to change the return type from `T` to
210-
// `impl Future<Output = T>` here because lower_body
211-
// only cares about the input argument patterns in the function
212-
// declaration (decl), not the return types.
213-
let coroutine_kind = header.coroutine_kind;
214-
let body_id = this.lower_maybe_coroutine_body(
215-
span,
216-
hir_id,
217-
decl,
218-
coroutine_kind,
219-
body.as_deref(),
220-
);
221-
209+
// We lower the generics before we lower the body since the body can bind the host
210+
// effect param via qualified paths of the form `<Type as ~const Trait>::AssocType`.
222211
let itctx = ImplTraitContext::Universal;
223212
let (generics, decl) =
224213
this.lower_generics(generics, header.constness, id, &itctx, |this| {
225214
this.lower_fn_decl(
226-
decl,
215+
ast_decl,
227216
id,
228217
*fn_sig_span,
229218
FnDeclKind::Fn,
230-
coroutine_kind,
219+
header.coroutine_kind,
231220
)
232221
});
222+
// Note: We don't need to change the return type from `T` to `impl Future<Output = T>`
223+
// here because `lower_body` only cares about the input argument patterns in the function
224+
// declaration `decl`, not the return types.
225+
let body_id = this.lower_maybe_coroutine_body(
226+
span,
227+
hir_id,
228+
ast_decl,
229+
header.coroutine_kind,
230+
body.as_deref(),
231+
);
233232
let sig = hir::FnSig {
234233
decl,
235234
header: this.lower_fn_header(*header),

compiler/rustc_ast_lowering/src/path.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
2727
// constness of the impl/bound if this is a trait path
2828
constness: Option<ast::BoundConstness>,
2929
) -> hir::QPath<'hir> {
30+
// FIXME(effects): The name isn't great.
31+
let trait_constness = qself.as_ref().map(|q| q.constness);
3032
let qself_position = qself.as_ref().map(|q| q.position);
3133
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
3234

@@ -76,8 +78,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
7678
param_mode,
7779
parenthesized_generic_args,
7880
itctx,
79-
// if this is the last segment, add constness to the trait path
80-
if i == proj_start - 1 { constness } else { None },
81+
// If this is the last segment, add constness to the trait path.
82+
// FIXME(effects): Is it possible that both constnesses are Some?
83+
if i == proj_start - 1 { constness } else { trait_constness },
8184
)
8285
},
8386
)),

compiler/rustc_ast_pretty/src/pprust/state.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,6 +1377,9 @@ impl<'a> State<'a> {
13771377
if qself.position > 0 {
13781378
self.space();
13791379
self.word_space("as");
1380+
if qself.constness != ast::BoundConstness::Never {
1381+
self.word_space(qself.constness.as_str());
1382+
}
13801383
let depth = path.segments.len() - qself.position;
13811384
self.print_path(path, false, depth);
13821385
}

compiler/rustc_hir_analysis/src/astconv/generics.rs

Lines changed: 129 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ use rustc_hir::def_id::DefId;
1212
use rustc_hir::GenericArg;
1313
use rustc_middle::ty::{
1414
self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt,
15+
TypeVisitableExt,
1516
};
1617
use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
1718
use rustc_span::{symbol::kw, Span};
19+
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
1820
use smallvec::SmallVec;
1921

2022
/// Report an error that a generic argument did not match the generic parameter that was
@@ -211,14 +213,39 @@ pub fn create_args_for_parent_generic_args<'tcx, 'a>(
211213
&& let GenericParamDefKind::Type { .. } = param.kind
212214
{
213215
args.push(
214-
self_ty.map(|ty| ty.into()).unwrap_or_else(|| ctx.inferred_kind(None, param, true)),
216+
self_ty
217+
.map(|ty| ty.into())
218+
.unwrap_or_else(|| ctx.inferred_kind(None, None, param, true)),
215219
);
216220
params.next();
217221
}
218222

219223
// Check whether this segment takes generic arguments and the user has provided any.
220224
let (hir_args, infer_args) = ctx.args_for_def_id(def_id);
221-
let mut hir_args = hir_args.iter().flat_map(|args| args.args.iter()).peekable();
225+
let hir_args = hir_args.iter().flat_map(|args| args.args.iter());
226+
227+
let host_effect = defs.host_effect_index.map(|index| {
228+
let arg = hir_args
229+
.clone()
230+
.rev()
231+
.find_map(|arg| match arg {
232+
hir::GenericArg::Const(arg) if arg.is_desugared_from_effects => {
233+
let did = arg.value.def_id;
234+
let param = defs.param_at(index, tcx);
235+
// FIXME(fmease): Add comment why.
236+
tcx.feed_anon_const_type(did, tcx.type_of(param.def_id));
237+
Some(ty::Const::from_anon_const(tcx, did))
238+
}
239+
_ => None,
240+
})
241+
// FIXME(effects): Don't hard-code the default of host effect params here. I guess
242+
// we could `tcx.const_param_default(tcx, param.def_id).no_bound_vars().unwrap()`
243+
// instead which isn't perfect either due to the assumption of “no bound vars”.
244+
.unwrap_or(tcx.consts.true_);
245+
(index, arg)
246+
});
247+
248+
let mut hir_args = hir_args.peekable();
222249

223250
// If we encounter a type or const when we expect a lifetime, we infer the lifetimes.
224251
// If we later encounter a lifetime, we know that the arguments were provided in the
@@ -256,7 +283,12 @@ pub fn create_args_for_parent_generic_args<'tcx, 'a>(
256283
// Since this is a const impl, we need to insert a host arg at the end of
257284
// `PartialEq`'s generics, but this errors since `Rhs` isn't specified.
258285
// To work around this, we infer all arguments until we reach the host param.
259-
args.push(ctx.inferred_kind(Some(&args), param, infer_args));
286+
args.push(ctx.inferred_kind(
287+
Some(&args),
288+
host_effect,
289+
param,
290+
infer_args,
291+
));
260292
params.next();
261293
}
262294
(GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _)
@@ -281,7 +313,7 @@ pub fn create_args_for_parent_generic_args<'tcx, 'a>(
281313
) => {
282314
// We expected a lifetime argument, but got a type or const
283315
// argument. That means we're inferring the lifetimes.
284-
args.push(ctx.inferred_kind(None, param, infer_args));
316+
args.push(ctx.inferred_kind(None, None, param, infer_args));
285317
force_infer_lt = Some((arg, param));
286318
params.next();
287319
}
@@ -377,7 +409,7 @@ pub fn create_args_for_parent_generic_args<'tcx, 'a>(
377409
(None, Some(&param)) => {
378410
// If there are fewer arguments than parameters, it means
379411
// we're inferring the remaining arguments.
380-
args.push(ctx.inferred_kind(Some(&args), param, infer_args));
412+
args.push(ctx.inferred_kind(Some(&args), host_effect, param, infer_args));
381413
params.next();
382414
}
383415

@@ -656,3 +688,95 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes(
656688
ExplicitLateBound::No
657689
}
658690
}
691+
692+
pub trait EarlyBinderExt<'tcx, T> {
693+
fn instantiate_with_host_effect(
694+
self,
695+
tcx: TyCtxt<'tcx>,
696+
args: &[ty::GenericArg<'tcx>],
697+
host_effect: Option<(usize, ty::Const<'tcx>)>,
698+
) -> T;
699+
}
700+
701+
impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> EarlyBinderExt<'tcx, T> for ty::EarlyBinder<T> {
702+
fn instantiate_with_host_effect(
703+
self,
704+
tcx: TyCtxt<'tcx>,
705+
args: &[ty::GenericArg<'tcx>],
706+
host_effect: Option<(usize, ty::Const<'tcx>)>,
707+
) -> T {
708+
let Some(host_effect) = host_effect else {
709+
return self.instantiate(tcx, args);
710+
};
711+
let mut folder = ArgFolder { tcx, args, host_effect, depth: ty::INNERMOST };
712+
self.skip_binder().fold_with(&mut folder)
713+
}
714+
}
715+
716+
struct ArgFolder<'a, 'tcx> {
717+
tcx: TyCtxt<'tcx>,
718+
args: &'a [ty::GenericArg<'tcx>],
719+
host_effect: (usize, ty::Const<'tcx>),
720+
depth: ty::DebruijnIndex,
721+
}
722+
723+
// FIXME: Proper panic messages.
724+
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ArgFolder<'_, 'tcx> {
725+
#[inline]
726+
fn interner(&self) -> TyCtxt<'tcx> {
727+
self.tcx
728+
}
729+
730+
fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
731+
&mut self,
732+
t: ty::Binder<'tcx, T>,
733+
) -> ty::Binder<'tcx, T> {
734+
self.depth.shift_in(1);
735+
let t = t.super_fold_with(self);
736+
self.depth.shift_out(1);
737+
t
738+
}
739+
740+
fn fold_region(&mut self, re: ty::Region<'tcx>) -> ty::Region<'tcx> {
741+
if let ty::ReEarlyParam(param) = *re {
742+
let arg = self.args.get(param.index as usize).map(|arg| arg.unpack());
743+
let Some(ty::GenericArgKind::Lifetime(re)) = arg else { bug!() };
744+
ty::fold::shift_vars(self.tcx, re, self.depth.as_u32())
745+
} else {
746+
re
747+
}
748+
}
749+
750+
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
751+
if !ty.has_param() {
752+
return ty;
753+
}
754+
if let ty::Param(param) = *ty.kind() {
755+
let arg = self.args.get(param.index as usize).map(|arg| arg.unpack());
756+
let Some(ty::GenericArgKind::Type(ty)) = arg else { bug!() };
757+
ty::fold::shift_vars(self.tcx, ty, self.depth.as_u32())
758+
} else {
759+
ty.super_fold_with(self)
760+
}
761+
}
762+
763+
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
764+
if !ct.has_param() {
765+
return ct;
766+
}
767+
if let ty::ConstKind::Param(param) = ct.kind() {
768+
let (host_effect_index, host_effect_arg) = self.host_effect;
769+
if param.index as usize == host_effect_index {
770+
assert!(self.depth == ty::INNERMOST || !host_effect_arg.has_escaping_bound_vars());
771+
eprintln!("::: subst({param:?} -> {host_effect_arg:?})");
772+
host_effect_arg
773+
} else {
774+
let arg = self.args.get(param.index as usize).map(|arg| arg.unpack());
775+
let Some(ty::GenericArgKind::Const(ct)) = arg else { bug!() };
776+
ty::fold::shift_vars(self.tcx, ct, self.depth.as_u32())
777+
}
778+
} else {
779+
ct.super_fold_with(self)
780+
}
781+
}
782+
}

compiler/rustc_hir_analysis/src/astconv/mod.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ mod lint;
99
mod object_safety;
1010

1111
use crate::astconv::errors::prohibit_assoc_ty_binding;
12+
use crate::astconv::generics::EarlyBinderExt;
1213
use crate::astconv::generics::{check_generic_arg_count, create_args_for_parent_generic_args};
1314
use crate::bounds::Bounds;
1415
use crate::collect::HirPlaceholderCollector;
@@ -226,6 +227,7 @@ pub trait CreateSubstsForGenericArgsCtxt<'a, 'tcx> {
226227
fn inferred_kind(
227228
&mut self,
228229
args: Option<&[ty::GenericArg<'tcx>]>,
230+
host_effect: Option<(usize, ty::Const<'tcx>)>,
229231
param: &ty::GenericParamDef,
230232
infer_args: bool,
231233
) -> ty::GenericArg<'tcx>;
@@ -464,9 +466,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
464466
(&GenericParamDefKind::Type { has_default, .. }, GenericArg::Infer(inf)) => {
465467
handle_ty_args(has_default, &inf.to_ty())
466468
}
467-
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
469+
(GenericParamDefKind::Const { is_host_effect, .. }, GenericArg::Const(ct)) => {
468470
let did = ct.value.def_id;
469-
tcx.feed_anon_const_type(did, tcx.type_of(param.def_id));
471+
// FIXME(fmease): We add comment why.
472+
if !is_host_effect {
473+
tcx.feed_anon_const_type(did, tcx.type_of(param.def_id));
474+
}
470475
ty::Const::from_anon_const(tcx, did).into()
471476
}
472477
(&GenericParamDefKind::Const { .. }, hir::GenericArg::Infer(inf)) => {
@@ -492,6 +497,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
492497
fn inferred_kind(
493498
&mut self,
494499
args: Option<&[ty::GenericArg<'tcx>]>,
500+
host_effect: Option<(usize, ty::Const<'tcx>)>,
495501
param: &ty::GenericParamDef,
496502
infer_args: bool,
497503
) -> ty::GenericArg<'tcx> {
@@ -522,7 +528,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
522528
// Avoid ICE #86756 when type error recovery goes awry.
523529
return Ty::new_misc_error(tcx).into();
524530
}
525-
tcx.at(self.span).type_of(param.def_id).instantiate(tcx, args).into()
531+
tcx.at(self.span)
532+
.type_of(param.def_id)
533+
.instantiate_with_host_effect(tcx, args, host_effect)
534+
.into()
526535
} else if infer_args {
527536
self.astconv.ty_infer(Some(param), self.span).into()
528537
} else {
@@ -539,10 +548,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
539548
if let Err(guar) = ty.error_reported() {
540549
return ty::Const::new_error(tcx, guar, ty).into();
541550
}
542-
// FIXME(effects) see if we should special case effect params here
543551
if !infer_args && has_default {
544552
tcx.const_param_default(param.def_id)
545-
.instantiate(tcx, args.unwrap())
553+
.instantiate_with_host_effect(tcx, args.unwrap(), host_effect)
546554
.into()
547555
} else {
548556
if infer_args {

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_hir::def_id::DefId;
1212
use rustc_hir::lang_items::LangItem;
1313
use rustc_hir::{ExprKind, GenericArg, Node, QPath};
1414
use rustc_hir_analysis::astconv::generics::{
15-
check_generic_arg_count_for_call, create_args_for_parent_generic_args,
15+
check_generic_arg_count_for_call, create_args_for_parent_generic_args, EarlyBinderExt,
1616
};
1717
use rustc_hir_analysis::astconv::{
1818
AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
@@ -1329,6 +1329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13291329
fn inferred_kind(
13301330
&mut self,
13311331
args: Option<&[ty::GenericArg<'tcx>]>,
1332+
host_effect: Option<(usize, ty::Const<'tcx>)>,
13321333
param: &ty::GenericParamDef,
13331334
infer_args: bool,
13341335
) -> ty::GenericArg<'tcx> {
@@ -1342,7 +1343,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13421343
// If we have a default, then it doesn't matter that we're not
13431344
// inferring the type arguments: we provide the default where any
13441345
// is missing.
1345-
tcx.type_of(param.def_id).instantiate(tcx, args.unwrap()).into()
1346+
tcx.type_of(param.def_id)
1347+
.instantiate_with_host_effect(tcx, args.unwrap(), host_effect)
1348+
.into()
13461349
} else {
13471350
// If no type arguments were provided, we have to infer them.
13481351
// This case also occurs as a result of some malformed input, e.g.
@@ -1367,7 +1370,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13671370
} else if !infer_args {
13681371
return tcx
13691372
.const_param_default(param.def_id)
1370-
.instantiate(tcx, args.unwrap())
1373+
.instantiate_with_host_effect(tcx, args.unwrap(), host_effect)
13711374
.into();
13721375
}
13731376
}

compiler/rustc_hir_typeck/src/method/confirm.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
424424
fn inferred_kind(
425425
&mut self,
426426
_args: Option<&[ty::GenericArg<'tcx>]>,
427+
_host_effect: Option<(usize, ty::Const<'tcx>)>,
427428
param: &ty::GenericParamDef,
428429
_infer_args: bool,
429430
) -> ty::GenericArg<'tcx> {

0 commit comments

Comments
 (0)