1
Fork 0

Rollup merge of #120549 - lcnr:errs-showcase, r=compiler-errors

modify alias-relate to also normalize ambiguous opaques

allows a bunch of further cleanups and generally simplifies the type system. To handle https://github.com/rust-lang/trait-system-refactor-initiative/issues/8 we'll have to add a some additional complexity to the `(Alias, Infer)` branches in alias-relate, so removing the opaque type special case here is really valuable.

It does worsen `deduce_closure_signature` and friends even more as they now receive an inference variable which is only constrained via an `AliasRelate` goal. These probably have to look into alias relate goals somehow. Leaving that for a future PR as this is something we'll have to tackle regardless.

r? `@compiler-errors`
This commit is contained in:
Matthias Krüger 2024-02-13 17:38:10 +01:00 committed by GitHub
commit 65ab663266
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 186 additions and 214 deletions

View file

@ -304,6 +304,10 @@ fn typeck_with_fallback<'tcx>(
let typeck_results = fcx.resolve_type_vars_in_body(body); let typeck_results = fcx.resolve_type_vars_in_body(body);
// We clone the defined opaque types during writeback in the new solver
// because we have to use them during normalization.
let _ = fcx.infcx.take_opaque_types();
// Consistency check our TypeckResults instance can hold all ItemLocalIds // Consistency check our TypeckResults instance can hold all ItemLocalIds
// it will need to hold. // it will need to hold.
assert_eq!(typeck_results.hir_owner, id.owner); assert_eq!(typeck_results.hir_owner, id.owner);

View file

@ -562,7 +562,15 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
fn visit_opaque_types(&mut self) { fn visit_opaque_types(&mut self) {
let opaque_types = self.fcx.infcx.take_opaque_types(); // We clone the opaques instead of stealing them here as they are still used for
// normalization in the next generation trait solver.
//
// FIXME(-Znext-solver): Opaque types defined after this would simply get dropped
// at the end of typeck. While this seems unlikely to happen in practice this
// should still get fixed. Either by preventing writeback from defining new opaque
// types or by using this function at the end of writeback and running it as a
// fixpoint.
let opaque_types = self.fcx.infcx.clone_opaque_types();
for (opaque_type_key, decl) in opaque_types { for (opaque_type_key, decl) in opaque_types {
let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span); let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span);
let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span); let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span);

View file

@ -1325,6 +1325,12 @@ impl<'tcx> InferCtxt<'tcx> {
std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types) std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types)
} }
#[instrument(level = "debug", skip(self), ret)]
pub fn clone_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> {
debug_assert_ne!(self.defining_use_anchor, DefiningAnchor::Error);
self.inner.borrow().opaque_type_storage.opaque_types.clone()
}
pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
self.resolve_vars_if_possible(t).to_string() self.resolve_vars_if_possible(t).to_string()
} }

View file

@ -3,33 +3,27 @@
//! of our more general approach to "lazy normalization". //! of our more general approach to "lazy normalization".
//! //!
//! This is done by first normalizing both sides of the goal, ending up in //! This is done by first normalizing both sides of the goal, ending up in
//! either a concrete type, rigid projection, opaque, or an infer variable. //! either a concrete type, rigid alias, or an infer variable.
//! These are related further according to the rules below: //! These are related further according to the rules below:
//! //!
//! (1.) If we end up with a rigid projection and a rigid projection, then we //! (1.) If we end up with two rigid aliases, then we relate them structurally.
//! relate those projections structurally.
//! //!
//! (2.) If we end up with a rigid projection and an alias, then the opaque will //! (2.) If we end up with an infer var and a rigid alias, then
//! have its hidden type defined to be that rigid projection.
//!
//! (3.) If we end up with an opaque and an opaque, then we assemble two
//! candidates, one defining the LHS to be the hidden type of the RHS, and vice
//! versa.
//!
//! (4.) If we end up with an infer var and an opaque or rigid projection, then
//! we assign the alias to the infer var. //! we assign the alias to the infer var.
//! //!
//! (5.) If we end up with an opaque and a rigid (non-projection) type, then we //! (3.) Otherwise, if we end with two rigid (non-projection) or infer types,
//! define the hidden type of the opaque to be the rigid type.
//!
//! (6.) Otherwise, if we end with two rigid (non-projection) or infer types,
//! relate them structurally. //! relate them structurally.
//!
//! Subtle: when relating an opaque to another type, we emit a
//! `NormalizesTo(opaque, ?fresh_var)` goal when trying to normalize the opaque.
//! This nested goal starts out as ambiguous and does not actually define the opaque.
//! However, if `?fresh_var` ends up geteting equated to another type, we retry the
//! `NormalizesTo` goal, at which point the opaque is actually defined.
use super::{EvalCtxt, GoalSource}; use super::{EvalCtxt, GoalSource};
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::query::NoSolution;
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
use rustc_middle::ty; use rustc_middle::ty::{self, Ty};
impl<'tcx> EvalCtxt<'_, 'tcx> { impl<'tcx> EvalCtxt<'_, 'tcx> {
#[instrument(level = "debug", skip(self), ret)] #[instrument(level = "debug", skip(self), ret)]
@ -59,37 +53,32 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} }
(Some(alias), None) => { (Some(_), None) => {
if rhs.is_infer() { if rhs.is_infer() {
self.relate(param_env, lhs, variance, rhs)?; self.relate(param_env, lhs, variance, rhs)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} else if alias.is_opaque(tcx) {
// FIXME: This doesn't account for variance.
self.define_opaque(param_env, alias, rhs)
} else { } else {
Err(NoSolution) Err(NoSolution)
} }
} }
(None, Some(alias)) => { (None, Some(_)) => {
if lhs.is_infer() { if lhs.is_infer() {
self.relate(param_env, lhs, variance, rhs)?; self.relate(param_env, lhs, variance, rhs)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} else if alias.is_opaque(tcx) {
// FIXME: This doesn't account for variance.
self.define_opaque(param_env, alias, lhs)
} else { } else {
Err(NoSolution) Err(NoSolution)
} }
} }
(Some(alias_lhs), Some(alias_rhs)) => { (Some(alias_lhs), Some(alias_rhs)) => {
self.relate_rigid_alias_or_opaque(param_env, alias_lhs, variance, alias_rhs) self.relate(param_env, alias_lhs, variance, alias_rhs)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} }
} }
} }
// FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var. // FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var.
/// Normalize the `term` to equate it later. This does not define opaque types. /// Normalize the `term` to equate it later.
#[instrument(level = "debug", skip(self, param_env), ret)] #[instrument(level = "debug", skip(self, param_env), ret)]
fn try_normalize_term( fn try_normalize_term(
&mut self, &mut self,
@ -98,10 +87,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
) -> Result<Option<ty::Term<'tcx>>, NoSolution> { ) -> Result<Option<ty::Term<'tcx>>, NoSolution> {
match term.unpack() { match term.unpack() {
ty::TermKind::Ty(ty) => { ty::TermKind::Ty(ty) => {
// We do no define opaque types here but instead do so in `relate_rigid_alias_or_opaque`. Ok(self.try_normalize_ty_recur(param_env, 0, ty).map(Into::into))
Ok(self
.try_normalize_ty_recur(param_env, DefineOpaqueTypes::No, 0, ty)
.map(Into::into))
} }
ty::TermKind::Const(_) => { ty::TermKind::Const(_) => {
if let Some(alias) = term.to_alias_ty(self.tcx()) { if let Some(alias) = term.to_alias_ty(self.tcx()) {
@ -119,51 +105,34 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
} }
} }
fn define_opaque( fn try_normalize_ty_recur(
&mut self, &mut self,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
opaque: ty::AliasTy<'tcx>, depth: usize,
term: ty::Term<'tcx>, ty: Ty<'tcx>,
) -> QueryResult<'tcx> { ) -> Option<Ty<'tcx>> {
self.add_goal( if !self.tcx().recursion_limit().value_within_limit(depth) {
GoalSource::Misc, return None;
Goal::new(self.tcx(), param_env, ty::NormalizesTo { alias: opaque, term }), }
let ty::Alias(_, alias) = *ty.kind() else {
return Some(ty);
};
match self.commit_if_ok(|this| {
let normalized_ty = this.next_ty_infer();
let normalizes_to_goal = Goal::new(
this.tcx(),
param_env,
ty::NormalizesTo { alias, term: normalized_ty.into() },
); );
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) this.add_goal(GoalSource::Misc, normalizes_to_goal);
} this.try_evaluate_added_goals()?;
let ty = this.resolve_vars_if_possible(normalized_ty);
fn relate_rigid_alias_or_opaque( Ok(this.try_normalize_ty_recur(param_env, depth + 1, ty))
&mut self, }) {
param_env: ty::ParamEnv<'tcx>, Ok(ty) => ty,
lhs: ty::AliasTy<'tcx>, Err(NoSolution) => Some(ty),
variance: ty::Variance,
rhs: ty::AliasTy<'tcx>,
) -> QueryResult<'tcx> {
let tcx = self.tcx();
let mut candidates = vec![];
if lhs.is_opaque(tcx) {
candidates.extend(
self.probe_misc_candidate("define-lhs-opaque")
.enter(|ecx| ecx.define_opaque(param_env, lhs, rhs.to_ty(tcx).into())),
);
}
if rhs.is_opaque(tcx) {
candidates.extend(
self.probe_misc_candidate("define-rhs-opaque")
.enter(|ecx| ecx.define_opaque(param_env, rhs, lhs.to_ty(tcx).into())),
);
}
candidates.extend(self.probe_misc_candidate("args-relate").enter(|ecx| {
ecx.relate(param_env, lhs, variance, rhs)?;
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}));
if let Some(result) = self.try_merge_responses(&candidates) {
Ok(result)
} else {
self.flounder(&candidates)
} }
} }
} }

View file

@ -276,11 +276,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
&mut self, &mut self,
goal: Goal<'tcx, G>, goal: Goal<'tcx, G>,
) -> Vec<Candidate<'tcx>> { ) -> Vec<Candidate<'tcx>> {
let Some(normalized_self_ty) = let Ok(normalized_self_ty) =
self.try_normalize_ty(goal.param_env, goal.predicate.self_ty()) self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty())
else { else {
debug!("overflow while evaluating self type"); return vec![];
return self.forced_ambiguity(MaybeCause::Overflow);
}; };
if normalized_self_ty.is_ty_var() { if normalized_self_ty.is_ty_var() {
@ -635,19 +634,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
return; return;
} }
match self.try_normalize_ty(goal.param_env, alias_ty.self_ty()) {
// Recurse on the self type of the projection. // Recurse on the self type of the projection.
Some(next_self_ty) => { match self.structurally_normalize_ty(goal.param_env, alias_ty.self_ty()) {
self.assemble_alias_bound_candidates_recur(next_self_ty, goal, candidates); Ok(next_self_ty) => {
} self.assemble_alias_bound_candidates_recur(next_self_ty, goal, candidates)
// Bail if we overflow when normalizing, adding an ambiguous candidate.
None => {
if let Ok(result) =
self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW)
{
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
}
} }
Err(NoSolution) => {}
} }
} }
@ -857,19 +849,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
let tcx = self.tcx(); let tcx = self.tcx();
let result = self.probe_misc_candidate("coherence unknowable").enter(|ecx| { let result = self.probe_misc_candidate("coherence unknowable").enter(|ecx| {
let trait_ref = goal.predicate.trait_ref(tcx); let trait_ref = goal.predicate.trait_ref(tcx);
#[derive(Debug)] let lazily_normalize_ty = |ty| ecx.structurally_normalize_ty(goal.param_env, ty);
struct Overflow;
let lazily_normalize_ty = |ty| match ecx.try_normalize_ty(goal.param_env, ty) {
Some(ty) => Ok(ty),
None => Err(Overflow),
};
match coherence::trait_ref_is_knowable(tcx, trait_ref, lazily_normalize_ty) { match coherence::trait_ref_is_knowable(tcx, trait_ref, lazily_normalize_ty)? {
Err(Overflow) => { Ok(()) => Err(NoSolution),
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW) Err(_) => {
}
Ok(Ok(())) => Err(NoSolution),
Ok(Err(_)) => {
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
} }
} }

View file

@ -15,15 +15,13 @@
//! about it on zulip. //! about it on zulip.
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::query::NoSolution;
use rustc_middle::infer::canonical::CanonicalVarInfos; use rustc_middle::infer::canonical::CanonicalVarInfos;
use rustc_middle::traits::solve::{ use rustc_middle::traits::solve::{
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack, CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack,
QueryResult, Response, QueryResult, Response,
}; };
use rustc_middle::traits::Reveal; use rustc_middle::ty::{self, AliasRelationDirection, Ty, TyCtxt, UniverseIndex};
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, UniverseIndex};
use rustc_middle::ty::{ use rustc_middle::ty::{
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate, CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
}; };
@ -267,71 +265,32 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
Ok(self.make_ambiguous_response_no_constraints(maybe_cause)) Ok(self.make_ambiguous_response_no_constraints(maybe_cause))
} }
/// Normalize a type when it is structually matched on. /// Normalize a type for when it is structurally matched on.
/// ///
/// In nearly all cases this function must be used before matching on a type. /// This function is necessary in nearly all cases before matching on a type.
/// Not doing so is likely to be incomplete and therefore unsound during /// Not doing so is likely to be incomplete and therefore unsound during
/// coherence. /// coherence.
#[instrument(level = "debug", skip(self), ret)] fn structurally_normalize_ty(
fn try_normalize_ty(
&mut self, &mut self,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>, ty: Ty<'tcx>,
) -> Option<Ty<'tcx>> { ) -> Result<Ty<'tcx>, NoSolution> {
self.try_normalize_ty_recur(param_env, DefineOpaqueTypes::Yes, 0, ty) if let ty::Alias(..) = ty.kind() {
} let normalized_ty = self.next_ty_infer();
let alias_relate_goal = Goal::new(
fn try_normalize_ty_recur( self.tcx(),
&mut self,
param_env: ty::ParamEnv<'tcx>,
define_opaque_types: DefineOpaqueTypes,
depth: usize,
ty: Ty<'tcx>,
) -> Option<Ty<'tcx>> {
if !self.tcx().recursion_limit().value_within_limit(depth) {
return None;
}
let ty::Alias(kind, alias) = *ty.kind() else {
return Some(ty);
};
// We do no always define opaque types eagerly to allow non-defining uses
// in the defining scope. However, if we can unify this opaque to an existing
// opaque, then we should attempt to eagerly reveal the opaque, and we fall
// through.
if let DefineOpaqueTypes::No = define_opaque_types
&& let Reveal::UserFacing = param_env.reveal()
&& let ty::Opaque = kind
&& let Some(def_id) = alias.def_id.as_local()
&& self.can_define_opaque_ty(def_id)
{
if self
.unify_existing_opaque_tys(
param_env, param_env,
OpaqueTypeKey { def_id, args: alias.args }, ty::PredicateKind::AliasRelate(
self.next_ty_infer(), ty.into(),
) normalized_ty.into(),
.is_empty() AliasRelationDirection::Equate,
{ ),
return Some(ty);
}
}
match self.commit_if_ok(|this| {
let normalized_ty = this.next_ty_infer();
let normalizes_to_goal = Goal::new(
this.tcx(),
param_env,
ty::NormalizesTo { alias, term: normalized_ty.into() },
); );
this.add_goal(GoalSource::Misc, normalizes_to_goal); self.add_goal(GoalSource::Misc, alias_relate_goal);
this.try_evaluate_added_goals()?; self.try_evaluate_added_goals()?;
let ty = this.resolve_vars_if_possible(normalized_ty); Ok(self.resolve_vars_if_possible(normalized_ty))
Ok(this.try_normalize_ty_recur(param_env, define_opaque_types, depth + 1, ty)) } else {
}) { Ok(ty)
Ok(ty) => ty,
Err(NoSolution) => Some(ty),
} }
} }
} }

View file

@ -58,21 +58,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
} }
} }
let expected = match self.try_normalize_ty(goal.param_env, expected) { let expected = self.structurally_normalize_ty(goal.param_env, expected)?;
Some(ty) => { if expected.is_ty_var() {
if ty.is_ty_var() {
return self.evaluate_added_goals_and_make_canonical_response(
Certainty::AMBIGUOUS,
);
} else {
ty
}
}
None => {
return self return self
.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW); .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
} }
};
// Otherwise, define a new opaque type // Otherwise, define a new opaque type
self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?; self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?;

View file

@ -584,11 +584,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
let a_ty = goal.predicate.self_ty(); let a_ty = goal.predicate.self_ty();
// We need to normalize the b_ty since it's matched structurally // We need to normalize the b_ty since it's matched structurally
// in the other functions below. // in the other functions below.
let b_ty = match ecx let Ok(b_ty) = ecx.structurally_normalize_ty(
.try_normalize_ty(goal.param_env, goal.predicate.trait_ref.args.type_at(1)) goal.param_env,
{ goal.predicate.trait_ref.args.type_at(1),
Some(b_ty) => b_ty, ) else {
None => return vec![misc_candidate(ecx, Certainty::OVERFLOW)], return vec![];
}; };
let goal = goal.with(ecx.tcx(), (a_ty, b_ty)); let goal = goal.with(ecx.tcx(), (a_ty, b_ty));

View file

@ -0,0 +1,23 @@
error[E0282]: type annotations needed
--> $DIR/recursive-coroutine-boxed.rs:10:23
|
LL | let mut gen = Box::pin(foo());
| ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Box`
...
LL | let mut r = gen.as_mut().resume(());
| ------ type must be known at this point
|
help: consider specifying the generic argument
|
LL | let mut gen = Box::<T>::pin(foo());
| +++++
error[E0282]: type annotations needed
--> $DIR/recursive-coroutine-boxed.rs:10:32
|
LL | let mut gen = Box::pin(foo());
| ^^^^^ cannot infer type for opaque type `impl Coroutine<Yield = (), Return = ()>`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0282`.

View file

@ -1,5 +1,5 @@
// check-pass
// revisions: current next // revisions: current next
//[current] check-pass
//[next] compile-flags: -Znext-solver //[next] compile-flags: -Znext-solver
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait)]
@ -8,6 +8,8 @@ use std::ops::{Coroutine, CoroutineState};
fn foo() -> impl Coroutine<Yield = (), Return = ()> { fn foo() -> impl Coroutine<Yield = (), Return = ()> {
|| { || {
let mut gen = Box::pin(foo()); let mut gen = Box::pin(foo());
//[next]~^ ERROR type annotations needed
//[next]~| ERROR type annotations needed
let mut r = gen.as_mut().resume(()); let mut r = gen.as_mut().resume(());
while let CoroutineState::Yielded(v) = r { while let CoroutineState::Yielded(v) = r {
yield v; yield v;

View file

@ -1,8 +1,8 @@
error[E0284]: type annotations needed: cannot satisfy `A <: B` error[E0284]: type annotations needed: cannot satisfy `A == B`
--> $DIR/two_tait_defining_each_other2.rs:11:5 --> $DIR/two_tait_defining_each_other2.rs:11:5
| |
LL | x // B's hidden type is A (opaquely) LL | x // B's hidden type is A (opaquely)
| ^ cannot satisfy `A <: B` | ^ cannot satisfy `A == B`
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -10,7 +10,7 @@ trait Foo {}
fn muh(x: A) -> B { fn muh(x: A) -> B {
x // B's hidden type is A (opaquely) x // B's hidden type is A (opaquely)
//[current]~^ ERROR opaque type's hidden type cannot be another opaque type //[current]~^ ERROR opaque type's hidden type cannot be another opaque type
//[next]~^^ ERROR type annotations needed: cannot satisfy `A <: B` //[next]~^^ ERROR type annotations needed: cannot satisfy `A == B`
} }
struct Bar; struct Bar;

View file

@ -1,9 +1,10 @@
// compile-flags: -Znext-solver // compile-flags: -Znext-solver
// check-pass // FIXME(-Znext-solver): This test is currently broken because the `deduce_closure_signature`
// is unable to look at nested obligations.
trait Foo { trait Foo {
fn test() -> impl Fn(u32) -> u32 { fn test() -> impl Fn(u32) -> u32 {
|x| x.count_ones() |x| x.count_ones()
//~^ ERROR type annotations needed
} }
} }

View file

@ -0,0 +1,14 @@
error[E0282]: type annotations needed
--> $DIR/deduce-closure-signature-after-normalization.rs:6:10
|
LL | |x| x.count_ones()
| ^ - type must be known at this point
|
help: consider giving this closure parameter an explicit type
|
LL | |x: /* Type */| x.count_ones()
| ++++++++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0282`.

View file

@ -1,16 +1,9 @@
error[E0283]: type annotations needed: cannot satisfy `Foo: Send` error[E0284]: type annotations needed: cannot satisfy `Foo == _`
--> $DIR/dont-type_of-tait-in-defining-scope.rs:15:18 --> $DIR/dont-type_of-tait-in-defining-scope.rs:15:18
| |
LL | needs_send::<Foo>(); LL | needs_send::<Foo>();
| ^^^ | ^^^ cannot satisfy `Foo == _`
|
= note: cannot satisfy `Foo: Send`
note: required by a bound in `needs_send`
--> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18
|
LL | fn needs_send<T: Send>() {}
| ^^^^ required by this bound in `needs_send`
error: aborting due to 1 previous error error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0283`. For more information about this error, try `rustc --explain E0284`.

View file

@ -1,16 +1,9 @@
error[E0283]: type annotations needed: cannot satisfy `Foo: Send` error[E0284]: type annotations needed: cannot satisfy `Foo == _`
--> $DIR/dont-type_of-tait-in-defining-scope.rs:15:18 --> $DIR/dont-type_of-tait-in-defining-scope.rs:15:18
| |
LL | needs_send::<Foo>(); LL | needs_send::<Foo>();
| ^^^ | ^^^ cannot satisfy `Foo == _`
|
= note: cannot satisfy `Foo: Send`
note: required by a bound in `needs_send`
--> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18
|
LL | fn needs_send<T: Send>() {}
| ^^^^ required by this bound in `needs_send`
error: aborting due to 1 previous error error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0283`. For more information about this error, try `rustc --explain E0284`.

View file

@ -13,7 +13,7 @@ fn needs_send<T: Send>() {}
fn test(_: Foo) { fn test(_: Foo) {
needs_send::<Foo>(); needs_send::<Foo>();
//~^ ERROR type annotations needed: cannot satisfy `Foo: Send` //~^ ERROR type annotations needed: cannot satisfy `Foo == _`
} }
fn defines(_: Foo) { fn defines(_: Foo) {

View file

@ -1,5 +1,5 @@
error[E0277]: can't compare `i32` with `Foo` error[E0277]: can't compare `i32` with `Foo`
--> $DIR/self-referential-2.rs:6:13 --> $DIR/self-referential-2.rs:9:13
| |
LL | fn bar() -> Bar { LL | fn bar() -> Bar {
| ^^^ no implementation for `i32 == Foo` | ^^^ no implementation for `i32 == Foo`

View file

@ -1,10 +1,13 @@
// revisions: current next
//[next] compile-flags: -Znext-solver
//[next] check-pass
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
type Foo = impl std::fmt::Debug; type Foo = impl std::fmt::Debug;
type Bar = impl PartialEq<Foo>; type Bar = impl PartialEq<Foo>;
fn bar() -> Bar { fn bar() -> Bar {
42_i32 //~^ ERROR can't compare `i32` with `Foo` 42_i32 //[current]~^ ERROR can't compare `i32` with `Foo`
} }
fn main() {} fn main() {}

View file

@ -0,0 +1,15 @@
error[E0284]: type annotations needed: cannot satisfy `Foo == _`
--> $DIR/type-alias-impl-trait-tuple.rs:21:24
|
LL | Blah { my_foo: make_foo(), my_u8: 12 }
| ^^^^^^^^^^ cannot satisfy `Foo == _`
error[E0284]: type annotations needed: cannot satisfy `Foo == _`
--> $DIR/type-alias-impl-trait-tuple.rs:25:10
|
LL | (self.my_foo, self.my_u8, make_foo())
| ^^^^^^^^^^^ cannot satisfy `Foo == _`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0284`.

View file

@ -1,4 +1,6 @@
// check-pass // revisions: current next
//[next] compile-flags: -Znext-solver
//[current] check-pass
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
#![allow(dead_code)] #![allow(dead_code)]
@ -17,9 +19,11 @@ struct Blah {
impl Blah { impl Blah {
fn new() -> Blah { fn new() -> Blah {
Blah { my_foo: make_foo(), my_u8: 12 } Blah { my_foo: make_foo(), my_u8: 12 }
//[next]~^ ERROR type annotations needed: cannot satisfy `Foo == _`
} }
fn into_inner(self) -> (Foo, u8, Foo) { fn into_inner(self) -> (Foo, u8, Foo) {
(self.my_foo, self.my_u8, make_foo()) (self.my_foo, self.my_u8, make_foo())
//[next]~^ ERROR type annotations needed: cannot satisfy `Foo == _`
} }
} }

View file

@ -1,5 +1,5 @@
error[E0382]: use of moved value: `x` error[E0382]: use of moved value: `x`
--> $DIR/type_of_a_let.rs:16:16 --> $DIR/type_of_a_let.rs:20:16
| |
LL | let x: Foo = 22_u32; LL | let x: Foo = 22_u32;
| - move occurs because `x` has type `Foo`, which does not implement the `Copy` trait | - move occurs because `x` has type `Foo`, which does not implement the `Copy` trait
@ -9,7 +9,7 @@ LL | same_type((x, y));
| ^ value used here after move | ^ value used here after move
error[E0382]: use of moved value: `y` error[E0382]: use of moved value: `y`
--> $DIR/type_of_a_let.rs:17:6 --> $DIR/type_of_a_let.rs:21:6
| |
LL | let y: Foo = x; LL | let y: Foo = x;
| - move occurs because `y` has type `Foo`, which does not implement the `Copy` trait | - move occurs because `y` has type `Foo`, which does not implement the `Copy` trait

View file

@ -1,3 +1,7 @@
// revisions: current next
//[next] compile-flags: -Znext-solver
//[next] check-pass
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
#![allow(dead_code)] #![allow(dead_code)]
@ -13,8 +17,8 @@ fn foo1() -> (u32, Foo) {
fn foo2() -> (u32, Foo) { fn foo2() -> (u32, Foo) {
let x: Foo = 22_u32; let x: Foo = 22_u32;
let y: Foo = x; let y: Foo = x;
same_type((x, y)); //~ ERROR use of moved value same_type((x, y)); //[current]~ ERROR use of moved value
(y, todo!()) //~ ERROR use of moved value (y, todo!()) //[current]~ ERROR use of moved value
} }
fn same_type<T>(x: (T, T)) {} fn same_type<T>(x: (T, T)) {}