diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index d84fabb783490..d369c5928df20 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -244,7 +244,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - if inferred_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() { + // FIXME(non_lifetime_binder): Don't infer a signature with late-bound ty/ct vars + if inferred_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() + && !inferred_sig.has_non_region_late_bound() + { expected_sig = inferred_sig; } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 8a2b800af0e81..8d9fa7489de93 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2735,6 +2735,7 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { | (ty::Infer(ty::InferTy::TyVar(_)), _) | (_, ty::Infer(ty::InferTy::TyVar(_))) => Ok(a), (ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Mismatch), + (ty::Bound(..), _) | (_, ty::Bound(..)) => Err(TypeError::Mismatch), _ => relate::super_relate_tys(self, a, b), } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index b3139d23d36e3..c46f2c13da7c7 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -700,12 +700,18 @@ pub trait PrettyPrinter<'tcx>: } ty::Error(_) => p!("[type error]"), ty::Param(ref param_ty) => p!(print(param_ty)), - ty::Bound(debruijn, bound_ty) => match bound_ty.kind { - ty::BoundTyKind::Anon(bv) => { - self.pretty_print_bound_var(debruijn, ty::BoundVar::from_u32(bv))? + ty::Bound(debruijn, bound_ty) => { + if self.should_print_verbose() { + p!(write("Bound({:?}, {:?})", debruijn, bound_ty)) + } else { + match bound_ty.kind { + ty::BoundTyKind::Anon(bv) => { + self.pretty_print_bound_var(debruijn, ty::BoundVar::from_u32(bv))? + } + ty::BoundTyKind::Param(_, s) => p!(write("{}", s)), + } } - ty::BoundTyKind::Param(_, s) => p!(write("{}", s)), - }, + } ty::Adt(def, substs) => { p!(print_def_path(def.did(), substs)); } @@ -736,8 +742,10 @@ pub trait PrettyPrinter<'tcx>: } } ty::Placeholder(placeholder) => match placeholder.name { - ty::BoundTyKind::Anon(_) => p!(write("Placeholder({:?})", placeholder)), - ty::BoundTyKind::Param(_, name) => p!(write("{}", name)), + ty::BoundTyKind::Param(_, name) if !self.should_print_verbose() => { + p!(write("{}", name)) + } + _ => p!(write("Placeholder({:?})", placeholder)), }, ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { // We use verbose printing in 'NO_QUERIES' mode, to diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 6814cadb9a8e4..9c682378ad9d9 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -83,6 +83,10 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable> { | TypeFlags::HAS_CT_PLACEHOLDER, ) } + /// True if there are any non-region placeholders + fn has_non_region_placeholders(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER) + } fn needs_subst(&self) -> bool { self.has_type_flags(TypeFlags::NEEDS_SUBST) } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 33c66d072e944..a518f7f93e44a 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -308,13 +308,22 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); let Some(tupled_inputs_and_output) = - structural_traits::extract_tupled_inputs_and_output_from_callable( - tcx, - goal.predicate.self_ty(), - goal_kind, - )? else { - return ecx.make_canonical_response(Certainty::AMBIGUOUS); - }; + structural_traits::extract_tupled_inputs_and_output_from_callable( + tcx, + goal.predicate.self_ty(), + goal_kind, + )? else { + return ecx.make_canonical_response(Certainty::AMBIGUOUS); + }; + + // FIXME(non_lifetime_binders): Higher-ranked Fn trait candidates are not (yet) supported. + // Make sure that the inputs/output don't capture any placeholder types. + if (goal.predicate.projection_ty.substs[1], goal.predicate.term) + .has_non_region_placeholders() + { + return Err(NoSolution); + } + let output_is_sized_pred = tupled_inputs_and_output .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output])); diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 5c499c36e9bf4..5f41aca492776 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -215,6 +215,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal_kind: ty::ClosureKind, ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); + + // FIXME(non_lifetime_binders): Higher-ranked Fn trait candidates are not (yet) supported. + // Check that the inputs don't capture any placeholder types. + if goal.predicate.trait_ref.substs[1].has_non_region_placeholders() { + return Err(NoSolution); + } + let Some(tupled_inputs_and_output) = structural_traits::extract_tupled_inputs_and_output_from_callable( tcx, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 21c158fd0fddd..9812d23d2b242 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -760,7 +760,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let trait_ref = self.closure_trait_ref_unnormalized(obligation, substs); - let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + + // FIXME(non_lifetime_binders): Perform the equivalent of a "leak check" here. + let mut nested = self.infcx.commit_if_ok(|_| { + let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + + if self + .infcx + .resolve_vars_if_possible(substs.as_closure().sig()) + .has_non_region_placeholders() + { + return Err(SelectionError::Unimplemented); + } + + Ok(nested) + })?; debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations"); diff --git a/tests/ui/nll/user-annotations/dump-fn-method.rs b/tests/ui/nll/user-annotations/dump-fn-method.rs index 148d63d848f80..12544ea69463e 100644 --- a/tests/ui/nll/user-annotations/dump-fn-method.rs +++ b/tests/ui/nll/user-annotations/dump-fn-method.rs @@ -1,8 +1,6 @@ // Unit test for the "user substitutions" that are annotated on each // node. -// compile-flags:-Zverbose - #![feature(rustc_attrs)] // Note: we reference the names T and U in the comments below. @@ -26,7 +24,7 @@ fn main() { let x = foo::; x(22); - let x = foo::<&'static u32>; //~ ERROR [&ReStatic u32] + let x = foo::<&'static u32>; //~ ERROR [&'static u32] x(&22); // Here: we only want the `T` to be given, the rest should be variables. @@ -41,7 +39,7 @@ fn main() { x(&22, 44, 66); // Here: all are given and we have a lifetime. - let x = >::method::; //~ ERROR [u8, &ReStatic u16, u32] + let x = >::method::; //~ ERROR [u8, &'static u16, u32] x(&22, &44, 66); // Here: we want in particular that *only* the method `U` diff --git a/tests/ui/nll/user-annotations/dump-fn-method.stderr b/tests/ui/nll/user-annotations/dump-fn-method.stderr index d139efa888ff7..970f8b82880bb 100644 --- a/tests/ui/nll/user-annotations/dump-fn-method.stderr +++ b/tests/ui/nll/user-annotations/dump-fn-method.stderr @@ -1,23 +1,23 @@ -error: user substs: UserSubsts { substs: [&ReStatic u32], user_self_ty: None } - --> $DIR/dump-fn-method.rs:29:13 +error: user substs: UserSubsts { substs: [&'static u32], user_self_ty: None } + --> $DIR/dump-fn-method.rs:27:13 | LL | let x = foo::<&'static u32>; | ^^^^^^^^^^^^^^^^^^^ error: user substs: UserSubsts { substs: [^0, u32, ^1], user_self_ty: None } - --> $DIR/dump-fn-method.rs:35:13 + --> $DIR/dump-fn-method.rs:33:13 | LL | let x = <_ as Bazoom>::method::<_>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: user substs: UserSubsts { substs: [u8, &ReStatic u16, u32], user_self_ty: None } - --> $DIR/dump-fn-method.rs:44:13 +error: user substs: UserSubsts { substs: [u8, &'static u16, u32], user_self_ty: None } + --> $DIR/dump-fn-method.rs:42:13 | LL | let x = >::method::; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: user substs: UserSubsts { substs: [^0, ^1, u32], user_self_ty: None } - --> $DIR/dump-fn-method.rs:52:5 + --> $DIR/dump-fn-method.rs:50:5 | LL | y.method::(44, 66); | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/non_lifetime_binders/closure-infer.classic.stderr b/tests/ui/traits/non_lifetime_binders/closure-infer.classic.stderr new file mode 100644 index 0000000000000..60b529bed587a --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/closure-infer.classic.stderr @@ -0,0 +1,58 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/closure-infer.rs:4:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: expected a `Fn<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:16:5: 16:8]` + --> $DIR/closure-infer.rs:12:15 + | +LL | fn take2() -> impl for Fn(T) -> T { + | ^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:16:5: 16:8]` + | + = help: the trait `Fn<(T,)>` is not implemented for closure `[closure@$DIR/closure-infer.rs:16:5: 16:8]` + +error[E0277]: expected a `FnOnce<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:16:5: 16:8]` + --> $DIR/closure-infer.rs:12:15 + | +LL | fn take2() -> impl for Fn(T) -> T { + | ^^^^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:16:5: 16:8]` + | + = help: the trait `FnOnce<(T,)>` is not implemented for closure `[closure@$DIR/closure-infer.rs:16:5: 16:8]` + +error[E0277]: expected a `Fn<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:20:10: 20:13]` + --> $DIR/closure-infer.rs:20:10 + | +LL | take(|x| x) + | ---- ^^^^^ expected an `Fn<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:20:10: 20:13]` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<(T,)>` is not implemented for closure `[closure@$DIR/closure-infer.rs:20:10: 20:13]` +note: required by a bound in `take` + --> $DIR/closure-infer.rs:7:18 + | +LL | fn take(id: impl for Fn(T) -> T) { + | ^^^^^^^^^^^^^^^^^ required by this bound in `take` + +error[E0277]: expected a `FnOnce<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:20:10: 20:13]` + --> $DIR/closure-infer.rs:20:10 + | +LL | take(|x| x) + | ---- ^^^^^ expected an `FnOnce<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:20:10: 20:13]` + | | + | required by a bound introduced by this call + | + = help: the trait `FnOnce<(T,)>` is not implemented for closure `[closure@$DIR/closure-infer.rs:20:10: 20:13]` +note: required by a bound in `take` + --> $DIR/closure-infer.rs:7:34 + | +LL | fn take(id: impl for Fn(T) -> T) { + | ^ required by this bound in `take` + +error: aborting due to 4 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/non_lifetime_binders/closure-infer.next.stderr b/tests/ui/traits/non_lifetime_binders/closure-infer.next.stderr new file mode 100644 index 0000000000000..c97fe0ebc083a --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/closure-infer.next.stderr @@ -0,0 +1,56 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/closure-infer.rs:4:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: expected a `Fn<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:16:5: 16:8]` + --> $DIR/closure-infer.rs:12:15 + | +LL | fn take2() -> impl for Fn(T) -> T { + | ^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:16:5: 16:8]` + | + = help: the trait `Fn<(T,)>` is not implemented for closure `[closure@$DIR/closure-infer.rs:16:5: 16:8]` + +error[E0271]: type mismatch resolving `<[closure@closure-infer.rs:16:5] as FnOnce<(T,)>>::Output == T` + --> $DIR/closure-infer.rs:12:15 + | +LL | fn take2() -> impl for Fn(T) -> T { + | ^^^^^^^^^^^^^^^^^^^^^^ types differ + +error[E0277]: expected a `Fn<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:20:10: 20:13]` + --> $DIR/closure-infer.rs:20:10 + | +LL | take(|x| x) + | ---- ^^^^^ expected an `Fn<(T,)>` closure, found `[closure@$DIR/closure-infer.rs:20:10: 20:13]` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<(T,)>` is not implemented for closure `[closure@$DIR/closure-infer.rs:20:10: 20:13]` +note: required by a bound in `take` + --> $DIR/closure-infer.rs:7:18 + | +LL | fn take(id: impl for Fn(T) -> T) { + | ^^^^^^^^^^^^^^^^^ required by this bound in `take` + +error[E0271]: type mismatch resolving `<[closure@closure-infer.rs:20:10] as FnOnce<(T,)>>::Output == T` + --> $DIR/closure-infer.rs:20:10 + | +LL | take(|x| x) + | ---- ^^^^^ types differ + | | + | required by a bound introduced by this call + | +note: required by a bound in `take` + --> $DIR/closure-infer.rs:7:34 + | +LL | fn take(id: impl for Fn(T) -> T) { + | ^ required by this bound in `take` + +error: aborting due to 4 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/non_lifetime_binders/closure-infer.rs b/tests/ui/traits/non_lifetime_binders/closure-infer.rs new file mode 100644 index 0000000000000..94ca06de2742b --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/closure-infer.rs @@ -0,0 +1,24 @@ +// revisions: classic next +//[next] compile-flags: -Ztrait-solver=next + +#![feature(non_lifetime_binders)] +//~^ WARNING the feature `non_lifetime_binders` is incomplete + +fn take(id: impl for Fn(T) -> T) { + id(0); + id(""); +} + +fn take2() -> impl for Fn(T) -> T { + //~^ ERROR expected a `Fn<(T,)>` closure, found + //[classic]~| ERROR expected a `FnOnce<(T,)>` closure, found + //[next]~| ERROR type mismatch resolving + |x| x +} + +fn main() { + take(|x| x) + //~^ ERROR expected a `Fn<(T,)>` closure, found + //[classic]~| ERROR expected a `FnOnce<(T,)>` closure, found + //[next]~| ERROR type mismatch resolving +}