Skip to content

Commit 8c57677

Browse files
authored
Rollup merge of rust-lang#62090 - davidtwco:ice-async-await-out-of-range-substitution, r=nikomatsakis
typeck: merge opaque type inference logic Fixes rust-lang#55872. See [relevant Zulip topic](https://rust-lang.zulipchat.com/#narrow/stream/187312-wg-async-foundations/topic/type.20parameter.20out.20of.20range.20.2355872). r? @nikomatsakis
2 parents 09ab31b + de8660a commit 8c57677

File tree

8 files changed

+217
-139
lines changed

8 files changed

+217
-139
lines changed

src/librustc/infer/opaque_types/mod.rs

+75-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::hir::Node;
44
use crate::infer::outlives::free_region_map::FreeRegionRelations;
55
use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin, TypeVariableOriginKind};
66
use crate::middle::region;
7+
use crate::mir::interpret::ConstValue;
78
use crate::traits::{self, PredicateObligation};
89
use crate::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
910
use crate::ty::subst::{InternalSubsts, Kind, SubstsRef, UnpackedKind};
@@ -553,6 +554,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
553554
def_id: DefId,
554555
opaque_defn: &OpaqueTypeDecl<'tcx>,
555556
instantiated_ty: Ty<'tcx>,
557+
span: Span,
556558
) -> Ty<'tcx> {
557559
debug!(
558560
"infer_opaque_definition_from_instantiation(def_id={:?}, instantiated_ty={:?})",
@@ -584,6 +586,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
584586
def_id,
585587
map,
586588
instantiated_ty,
589+
span,
587590
));
588591
debug!("infer_opaque_definition_from_instantiation: definition_ty={:?}", definition_ty);
589592

@@ -761,6 +764,9 @@ struct ReverseMapper<'tcx> {
761764

762765
/// initially `Some`, set to `None` once error has been reported
763766
hidden_ty: Option<Ty<'tcx>>,
767+
768+
/// Span of function being checked.
769+
span: Span,
764770
}
765771

766772
impl ReverseMapper<'tcx> {
@@ -770,6 +776,7 @@ impl ReverseMapper<'tcx> {
770776
opaque_type_def_id: DefId,
771777
map: FxHashMap<Kind<'tcx>, Kind<'tcx>>,
772778
hidden_ty: Ty<'tcx>,
779+
span: Span,
773780
) -> Self {
774781
Self {
775782
tcx,
@@ -778,6 +785,7 @@ impl ReverseMapper<'tcx> {
778785
map,
779786
map_missing_regions_to_empty: false,
780787
hidden_ty: Some(hidden_ty),
788+
span,
781789
}
782790
}
783791

@@ -812,10 +820,11 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
812820
_ => { }
813821
}
814822

823+
let generics = self.tcx().generics_of(self.opaque_type_def_id);
815824
match self.map.get(&r.into()).map(|k| k.unpack()) {
816825
Some(UnpackedKind::Lifetime(r1)) => r1,
817826
Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
818-
None => {
827+
None if generics.parent.is_some() => {
819828
if !self.map_missing_regions_to_empty && !self.tainted_by_errors {
820829
if let Some(hidden_ty) = self.hidden_ty.take() {
821830
unexpected_hidden_region_diagnostic(
@@ -829,6 +838,21 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
829838
}
830839
self.tcx.lifetimes.re_empty
831840
}
841+
None => {
842+
self.tcx.sess
843+
.struct_span_err(
844+
self.span,
845+
"non-defining existential type use in defining scope"
846+
)
847+
.span_label(
848+
self.span,
849+
format!("lifetime `{}` is part of concrete type but not used in \
850+
parameter list of existential type", r),
851+
)
852+
.emit();
853+
854+
self.tcx().global_tcx().mk_region(ty::ReStatic)
855+
},
832856
}
833857
}
834858

@@ -890,9 +914,59 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
890914
self.tcx.mk_generator(def_id, ty::GeneratorSubsts { substs }, movability)
891915
}
892916

917+
ty::Param(..) => {
918+
// Look it up in the substitution list.
919+
match self.map.get(&ty.into()).map(|k| k.unpack()) {
920+
// Found it in the substitution list; replace with the parameter from the
921+
// existential type.
922+
Some(UnpackedKind::Type(t1)) => t1,
923+
Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
924+
None => {
925+
self.tcx.sess
926+
.struct_span_err(
927+
self.span,
928+
&format!("type parameter `{}` is part of concrete type but not \
929+
used in parameter list for existential type", ty),
930+
)
931+
.emit();
932+
933+
self.tcx().types.err
934+
}
935+
}
936+
}
937+
893938
_ => ty.super_fold_with(self),
894939
}
895940
}
941+
942+
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
943+
trace!("checking const {:?}", ct);
944+
// Find a const parameter
945+
match ct.val {
946+
ConstValue::Param(..) => {
947+
// Look it up in the substitution list.
948+
match self.map.get(&ct.into()).map(|k| k.unpack()) {
949+
// Found it in the substitution list, replace with the parameter from the
950+
// existential type.
951+
Some(UnpackedKind::Const(c1)) => c1,
952+
Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
953+
None => {
954+
self.tcx.sess
955+
.struct_span_err(
956+
self.span,
957+
&format!("const parameter `{}` is part of concrete type but not \
958+
used in parameter list for existential type", ct)
959+
)
960+
.emit();
961+
962+
self.tcx().consts.err
963+
}
964+
}
965+
}
966+
967+
_ => ct,
968+
}
969+
}
896970
}
897971

898972
struct Instantiator<'a, 'tcx> {

src/librustc_typeck/check/writeback.rs

+15-138
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@ use rustc::hir::def_id::{DefId, DefIndex};
99
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
1010
use rustc::infer::InferCtxt;
1111
use rustc::ty::adjustment::{Adjust, Adjustment, PointerCast};
12-
use rustc::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder};
13-
use rustc::ty::subst::UnpackedKind;
12+
use rustc::ty::fold::{TypeFoldable, TypeFolder};
1413
use rustc::ty::{self, Ty, TyCtxt};
15-
use rustc::mir::interpret::ConstValue;
1614
use rustc::util::nodemap::DefIdSet;
1715
use rustc_data_structures::sync::Lrc;
1816
use std::mem;
@@ -440,141 +438,20 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
440438

441439
debug_assert!(!instantiated_ty.has_escaping_bound_vars());
442440

443-
let generics = self.tcx().generics_of(def_id);
444-
445-
let definition_ty = if generics.parent.is_some() {
446-
// `impl Trait`
447-
self.fcx.infer_opaque_definition_from_instantiation(
448-
def_id,
449-
opaque_defn,
450-
instantiated_ty,
451-
)
452-
} else {
453-
// Prevent:
454-
// * `fn foo<T>() -> Foo<T>`
455-
// * `fn foo<T: Bound + Other>() -> Foo<T>`
456-
// from being defining.
457-
458-
// Also replace all generic params with the ones from the existential type
459-
// definition so that
460-
// ```rust
461-
// existential type Foo<T>: 'static;
462-
// fn foo<U>() -> Foo<U> { .. }
463-
// ```
464-
// figures out the concrete type with `U`, but the stored type is with `T`.
465-
instantiated_ty.fold_with(&mut BottomUpFolder {
466-
tcx: self.tcx().global_tcx(),
467-
ty_op: |ty| {
468-
trace!("checking type {:?}", ty);
469-
// Find a type parameter.
470-
if let ty::Param(..) = ty.sty {
471-
// Look it up in the substitution list.
472-
assert_eq!(opaque_defn.substs.len(), generics.params.len());
473-
for (subst, param) in opaque_defn.substs.iter().zip(&generics.params) {
474-
if let UnpackedKind::Type(subst) = subst.unpack() {
475-
if subst == ty {
476-
// Found it in the substitution list; replace with the
477-
// parameter from the existential type.
478-
return self.tcx()
479-
.global_tcx()
480-
.mk_ty_param(param.index, param.name);
481-
}
482-
}
483-
}
484-
self.tcx()
485-
.sess
486-
.struct_span_err(
487-
span,
488-
&format!(
489-
"type parameter `{}` is part of concrete type but not used \
490-
in parameter list for existential type",
491-
ty,
492-
),
493-
)
494-
.emit();
495-
return self.tcx().types.err;
496-
}
497-
ty
498-
},
499-
lt_op: |region| {
500-
match region {
501-
// Skip static and bound regions: they don't require substitution.
502-
ty::ReStatic | ty::ReLateBound(..) => region,
503-
_ => {
504-
trace!("checking {:?}", region);
505-
for (subst, p) in opaque_defn.substs.iter().zip(&generics.params) {
506-
if let UnpackedKind::Lifetime(subst) = subst.unpack() {
507-
if subst == region {
508-
// Found it in the substitution list; replace with the
509-
// parameter from the existential type.
510-
let reg = ty::EarlyBoundRegion {
511-
def_id: p.def_id,
512-
index: p.index,
513-
name: p.name,
514-
};
515-
trace!("replace {:?} with {:?}", region, reg);
516-
return self.tcx()
517-
.global_tcx()
518-
.mk_region(ty::ReEarlyBound(reg));
519-
}
520-
}
521-
}
522-
trace!("opaque_defn: {:#?}", opaque_defn);
523-
trace!("generics: {:#?}", generics);
524-
self.tcx()
525-
.sess
526-
.struct_span_err(
527-
span,
528-
"non-defining existential type use in defining scope",
529-
)
530-
.span_label(
531-
span,
532-
format!(
533-
"lifetime `{}` is part of concrete type but not used \
534-
in parameter list of existential type",
535-
region,
536-
),
537-
)
538-
.emit();
539-
self.tcx().global_tcx().mk_region(ty::ReStatic)
540-
}
541-
}
542-
},
543-
ct_op: |ct| {
544-
trace!("checking const {:?}", ct);
545-
// Find a const parameter
546-
if let ConstValue::Param(..) = ct.val {
547-
// look it up in the substitution list
548-
assert_eq!(opaque_defn.substs.len(), generics.params.len());
549-
for (subst, param) in opaque_defn.substs.iter()
550-
.zip(&generics.params) {
551-
if let UnpackedKind::Const(subst) = subst.unpack() {
552-
if subst == ct {
553-
// found it in the substitution list, replace with the
554-
// parameter from the existential type
555-
return self.tcx()
556-
.global_tcx()
557-
.mk_const_param(param.index, param.name, ct.ty);
558-
}
559-
}
560-
}
561-
self.tcx()
562-
.sess
563-
.struct_span_err(
564-
span,
565-
&format!(
566-
"const parameter `{}` is part of concrete type but not \
567-
used in parameter list for existential type",
568-
ct,
569-
),
570-
)
571-
.emit();
572-
return self.tcx().consts.err;
573-
}
574-
ct
575-
}
576-
})
577-
};
441+
// Prevent:
442+
// * `fn foo<T>() -> Foo<T>`
443+
// * `fn foo<T: Bound + Other>() -> Foo<T>`
444+
// from being defining.
445+
446+
// Also replace all generic params with the ones from the existential type
447+
// definition so that
448+
// ```rust
449+
// existential type Foo<T>: 'static;
450+
// fn foo<U>() -> Foo<U> { .. }
451+
// ```
452+
// figures out the concrete type with `U`, but the stored type is with `T`.
453+
let definition_ty = self.fcx.infer_opaque_definition_from_instantiation(
454+
def_id, opaque_defn, instantiated_ty, span);
578455

579456
if let ty::Opaque(defin_ty_def_id, _substs) = definition_ty.sty {
580457
if def_id == defin_ty_def_id {
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// ignore-tidy-linelength
2+
#![feature(existential_type)]
3+
4+
pub trait Bar
5+
{
6+
type E: Copy;
7+
8+
fn foo<T>() -> Self::E;
9+
}
10+
11+
impl<S: Default> Bar for S {
12+
existential type E: Copy;
13+
//~^ ERROR the trait bound `S: std::marker::Copy` is not satisfied in `(S, T)` [E0277]
14+
//~^^ ERROR the trait bound `T: std::marker::Copy` is not satisfied in `(S, T)` [E0277]
15+
16+
fn foo<T: Default>() -> Self::E {
17+
//~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for existential type
18+
(S::default(), T::default())
19+
}
20+
}
21+
22+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
error[E0277]: the trait bound `S: std::marker::Copy` is not satisfied in `(S, T)`
2+
--> $DIR/issue-55872-1.rs:12:5
3+
|
4+
LL | existential type E: Copy;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `S`
6+
|
7+
= help: consider adding a `where S: std::marker::Copy` bound
8+
= note: required because it appears within the type `(S, T)`
9+
= note: the return type of a function must have a statically known size
10+
11+
error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied in `(S, T)`
12+
--> $DIR/issue-55872-1.rs:12:5
13+
|
14+
LL | existential type E: Copy;
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `T`
16+
|
17+
= help: consider adding a `where T: std::marker::Copy` bound
18+
= note: required because it appears within the type `(S, T)`
19+
= note: the return type of a function must have a statically known size
20+
21+
error: type parameter `T` is part of concrete type but not used in parameter list for existential type
22+
--> $DIR/issue-55872-1.rs:16:37
23+
|
24+
LL | fn foo<T: Default>() -> Self::E {
25+
| _____________________________________^
26+
LL | |
27+
LL | | (S::default(), T::default())
28+
LL | | }
29+
| |_____^
30+
31+
error: aborting due to 3 previous errors
32+
33+
For more information about this error, try `rustc --explain E0277`.
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// edition:2018
2+
// ignore-tidy-linelength
3+
#![feature(async_await, existential_type)]
4+
5+
pub trait Bar {
6+
type E: Copy;
7+
8+
fn foo<T>() -> Self::E;
9+
}
10+
11+
impl<S> Bar for S {
12+
existential type E: Copy;
13+
//~^ ERROR the trait bound `impl std::future::Future: std::marker::Copy` is not satisfied [E0277]
14+
fn foo<T>() -> Self::E {
15+
//~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for existential type
16+
async {}
17+
}
18+
}
19+
20+
fn main() {}

0 commit comments

Comments
 (0)