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:
commit
65ab663266
@ -304,6 +304,10 @@ fn typeck_with_fallback<'tcx>(
|
||||
|
||||
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
|
||||
// it will need to hold.
|
||||
assert_eq!(typeck_results.hir_owner, id.owner);
|
||||
|
@ -562,7 +562,15 @@ fn visit_coroutine_interior(&mut self) {
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
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 {
|
||||
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);
|
||||
|
@ -1325,6 +1325,12 @@ pub fn take_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> {
|
||||
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 {
|
||||
self.resolve_vars_if_possible(t).to_string()
|
||||
}
|
||||
|
@ -3,33 +3,27 @@
|
||||
//! of our more general approach to "lazy normalization".
|
||||
//!
|
||||
//! 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:
|
||||
//!
|
||||
//! (1.) If we end up with a rigid projection and a rigid projection, then we
|
||||
//! relate those projections structurally.
|
||||
//! (1.) If we end up with two rigid aliases, then we relate them structurally.
|
||||
//!
|
||||
//! (2.) If we end up with a rigid projection and an alias, then the opaque will
|
||||
//! 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
|
||||
//! (2.) If we end up with an infer var and a rigid alias, then
|
||||
//! we assign the alias to the infer var.
|
||||
//!
|
||||
//! (5.) If we end up with an opaque and a rigid (non-projection) type, then we
|
||||
//! 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,
|
||||
//! (3.) Otherwise, if we end with two rigid (non-projection) or infer types,
|
||||
//! 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 rustc_infer::infer::DefineOpaqueTypes;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
@ -59,37 +53,32 @@ pub(super) fn compute_alias_relate_goal(
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
|
||||
(Some(alias), None) => {
|
||||
(Some(_), None) => {
|
||||
if rhs.is_infer() {
|
||||
self.relate(param_env, lhs, variance, rhs)?;
|
||||
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 {
|
||||
Err(NoSolution)
|
||||
}
|
||||
}
|
||||
(None, Some(alias)) => {
|
||||
(None, Some(_)) => {
|
||||
if lhs.is_infer() {
|
||||
self.relate(param_env, lhs, variance, rhs)?;
|
||||
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 {
|
||||
Err(NoSolution)
|
||||
}
|
||||
}
|
||||
|
||||
(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.
|
||||
/// 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)]
|
||||
fn try_normalize_term(
|
||||
&mut self,
|
||||
@ -98,10 +87,7 @@ fn try_normalize_term(
|
||||
) -> Result<Option<ty::Term<'tcx>>, NoSolution> {
|
||||
match term.unpack() {
|
||||
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, DefineOpaqueTypes::No, 0, ty)
|
||||
.map(Into::into))
|
||||
Ok(self.try_normalize_ty_recur(param_env, 0, ty).map(Into::into))
|
||||
}
|
||||
ty::TermKind::Const(_) => {
|
||||
if let Some(alias) = term.to_alias_ty(self.tcx()) {
|
||||
@ -119,51 +105,34 @@ fn try_normalize_term(
|
||||
}
|
||||
}
|
||||
|
||||
fn define_opaque(
|
||||
fn try_normalize_ty_recur(
|
||||
&mut self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
opaque: ty::AliasTy<'tcx>,
|
||||
term: ty::Term<'tcx>,
|
||||
) -> QueryResult<'tcx> {
|
||||
self.add_goal(
|
||||
GoalSource::Misc,
|
||||
Goal::new(self.tcx(), param_env, ty::NormalizesTo { alias: opaque, term }),
|
||||
depth: usize,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<Ty<'tcx>> {
|
||||
if !self.tcx().recursion_limit().value_within_limit(depth) {
|
||||
return None;
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fn relate_rigid_alias_or_opaque(
|
||||
&mut self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
lhs: ty::AliasTy<'tcx>,
|
||||
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)
|
||||
this.add_goal(GoalSource::Misc, normalizes_to_goal);
|
||||
this.try_evaluate_added_goals()?;
|
||||
let ty = this.resolve_vars_if_possible(normalized_ty);
|
||||
Ok(this.try_normalize_ty_recur(param_env, depth + 1, ty))
|
||||
}) {
|
||||
Ok(ty) => ty,
|
||||
Err(NoSolution) => Some(ty),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -276,11 +276,10 @@ pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<'tcx>>(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, G>,
|
||||
) -> Vec<Candidate<'tcx>> {
|
||||
let Some(normalized_self_ty) =
|
||||
self.try_normalize_ty(goal.param_env, goal.predicate.self_ty())
|
||||
let Ok(normalized_self_ty) =
|
||||
self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty())
|
||||
else {
|
||||
debug!("overflow while evaluating self type");
|
||||
return self.forced_ambiguity(MaybeCause::Overflow);
|
||||
return vec![];
|
||||
};
|
||||
|
||||
if normalized_self_ty.is_ty_var() {
|
||||
@ -635,19 +634,12 @@ fn assemble_alias_bound_candidates_recur<G: GoalKind<'tcx>>(
|
||||
return;
|
||||
}
|
||||
|
||||
match self.try_normalize_ty(goal.param_env, alias_ty.self_ty()) {
|
||||
// Recurse on the self type of the projection.
|
||||
Some(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 });
|
||||
}
|
||||
match self.structurally_normalize_ty(goal.param_env, alias_ty.self_ty()) {
|
||||
Ok(next_self_ty) => {
|
||||
self.assemble_alias_bound_candidates_recur(next_self_ty, goal, candidates)
|
||||
}
|
||||
Err(NoSolution) => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -857,19 +849,11 @@ fn assemble_coherence_unknowable_candidates<G: GoalKind<'tcx>>(
|
||||
let tcx = self.tcx();
|
||||
let result = self.probe_misc_candidate("coherence unknowable").enter(|ecx| {
|
||||
let trait_ref = goal.predicate.trait_ref(tcx);
|
||||
#[derive(Debug)]
|
||||
struct Overflow;
|
||||
let lazily_normalize_ty = |ty| match ecx.try_normalize_ty(goal.param_env, ty) {
|
||||
Some(ty) => Ok(ty),
|
||||
None => Err(Overflow),
|
||||
};
|
||||
let lazily_normalize_ty = |ty| ecx.structurally_normalize_ty(goal.param_env, ty);
|
||||
|
||||
match coherence::trait_ref_is_knowable(tcx, trait_ref, lazily_normalize_ty) {
|
||||
Err(Overflow) => {
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW)
|
||||
}
|
||||
Ok(Ok(())) => Err(NoSolution),
|
||||
Ok(Err(_)) => {
|
||||
match coherence::trait_ref_is_knowable(tcx, trait_ref, lazily_normalize_ty)? {
|
||||
Ok(()) => Err(NoSolution),
|
||||
Err(_) => {
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||
}
|
||||
}
|
||||
|
@ -15,15 +15,13 @@
|
||||
//! about it on zulip.
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
|
||||
use rustc_infer::infer::DefineOpaqueTypes;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_middle::infer::canonical::CanonicalVarInfos;
|
||||
use rustc_middle::traits::solve::{
|
||||
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack,
|
||||
QueryResult, Response,
|
||||
};
|
||||
use rustc_middle::traits::Reveal;
|
||||
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, UniverseIndex};
|
||||
use rustc_middle::ty::{self, AliasRelationDirection, Ty, TyCtxt, UniverseIndex};
|
||||
use rustc_middle::ty::{
|
||||
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
|
||||
};
|
||||
@ -267,71 +265,32 @@ fn flounder(&mut self, responses: &[CanonicalResponse<'tcx>]) -> QueryResult<'tc
|
||||
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
|
||||
/// coherence.
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn try_normalize_ty(
|
||||
fn structurally_normalize_ty(
|
||||
&mut self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<Ty<'tcx>> {
|
||||
self.try_normalize_ty_recur(param_env, DefineOpaqueTypes::Yes, 0, ty)
|
||||
}
|
||||
|
||||
fn try_normalize_ty_recur(
|
||||
&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(
|
||||
) -> Result<Ty<'tcx>, NoSolution> {
|
||||
if let ty::Alias(..) = ty.kind() {
|
||||
let normalized_ty = self.next_ty_infer();
|
||||
let alias_relate_goal = Goal::new(
|
||||
self.tcx(),
|
||||
param_env,
|
||||
OpaqueTypeKey { def_id, args: alias.args },
|
||||
self.next_ty_infer(),
|
||||
)
|
||||
.is_empty()
|
||||
{
|
||||
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() },
|
||||
ty::PredicateKind::AliasRelate(
|
||||
ty.into(),
|
||||
normalized_ty.into(),
|
||||
AliasRelationDirection::Equate,
|
||||
),
|
||||
);
|
||||
this.add_goal(GoalSource::Misc, normalizes_to_goal);
|
||||
this.try_evaluate_added_goals()?;
|
||||
let ty = this.resolve_vars_if_possible(normalized_ty);
|
||||
Ok(this.try_normalize_ty_recur(param_env, define_opaque_types, depth + 1, ty))
|
||||
}) {
|
||||
Ok(ty) => ty,
|
||||
Err(NoSolution) => Some(ty),
|
||||
self.add_goal(GoalSource::Misc, alias_relate_goal);
|
||||
self.try_evaluate_added_goals()?;
|
||||
Ok(self.resolve_vars_if_possible(normalized_ty))
|
||||
} else {
|
||||
Ok(ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,21 +58,11 @@ pub(super) fn normalize_opaque_type(
|
||||
}
|
||||
}
|
||||
|
||||
let expected = match self.try_normalize_ty(goal.param_env, expected) {
|
||||
Some(ty) => {
|
||||
if ty.is_ty_var() {
|
||||
return self.evaluate_added_goals_and_make_canonical_response(
|
||||
Certainty::AMBIGUOUS,
|
||||
);
|
||||
} else {
|
||||
ty
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let expected = self.structurally_normalize_ty(goal.param_env, expected)?;
|
||||
if expected.is_ty_var() {
|
||||
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
|
||||
self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?;
|
||||
|
@ -584,11 +584,11 @@ fn consider_structural_builtin_unsize_candidates(
|
||||
let a_ty = goal.predicate.self_ty();
|
||||
// We need to normalize the b_ty since it's matched structurally
|
||||
// in the other functions below.
|
||||
let b_ty = match ecx
|
||||
.try_normalize_ty(goal.param_env, goal.predicate.trait_ref.args.type_at(1))
|
||||
{
|
||||
Some(b_ty) => b_ty,
|
||||
None => return vec![misc_candidate(ecx, Certainty::OVERFLOW)],
|
||||
let Ok(b_ty) = ecx.structurally_normalize_ty(
|
||||
goal.param_env,
|
||||
goal.predicate.trait_ref.args.type_at(1),
|
||||
) else {
|
||||
return vec![];
|
||||
};
|
||||
|
||||
let goal = goal.with(ecx.tcx(), (a_ty, b_ty));
|
||||
|
23
tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr
Normal file
23
tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr
Normal 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`.
|
@ -1,5 +1,5 @@
|
||||
// check-pass
|
||||
// revisions: current next
|
||||
//[current] check-pass
|
||||
//[next] compile-flags: -Znext-solver
|
||||
#![feature(coroutines, coroutine_trait)]
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
fn foo() -> impl Coroutine<Yield = (), Return = ()> {
|
||||
|| {
|
||||
let mut gen = Box::pin(foo());
|
||||
//[next]~^ ERROR type annotations needed
|
||||
//[next]~| ERROR type annotations needed
|
||||
let mut r = gen.as_mut().resume(());
|
||||
while let CoroutineState::Yielded(v) = r {
|
||||
yield v;
|
||||
|
@ -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
|
||||
|
|
||||
LL | x // B's hidden type is A (opaquely)
|
||||
| ^ cannot satisfy `A <: B`
|
||||
| ^ cannot satisfy `A == B`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
@ -10,7 +10,7 @@ trait Foo {}
|
||||
fn muh(x: A) -> B {
|
||||
x // B's hidden type is A (opaquely)
|
||||
//[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;
|
||||
|
@ -1,9 +1,10 @@
|
||||
// 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 {
|
||||
fn test() -> impl Fn(u32) -> u32 {
|
||||
|x| x.count_ones()
|
||||
//~^ ERROR type annotations needed
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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`.
|
@ -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
|
||||
|
|
||||
LL | needs_send::<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`
|
||||
| ^^^ cannot satisfy `Foo == _`
|
||||
|
||||
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`.
|
||||
|
@ -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
|
||||
|
|
||||
LL | needs_send::<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`
|
||||
| ^^^ cannot satisfy `Foo == _`
|
||||
|
||||
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`.
|
||||
|
@ -13,7 +13,7 @@ fn needs_send<T: Send>() {}
|
||||
|
||||
fn test(_: Foo) {
|
||||
needs_send::<Foo>();
|
||||
//~^ ERROR type annotations needed: cannot satisfy `Foo: Send`
|
||||
//~^ ERROR type annotations needed: cannot satisfy `Foo == _`
|
||||
}
|
||||
|
||||
fn defines(_: Foo) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
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 {
|
||||
| ^^^ no implementation for `i32 == Foo`
|
@ -1,10 +1,13 @@
|
||||
// revisions: current next
|
||||
//[next] compile-flags: -Znext-solver
|
||||
//[next] check-pass
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
type Foo = impl std::fmt::Debug;
|
||||
type Bar = impl PartialEq<Foo>;
|
||||
|
||||
fn bar() -> Bar {
|
||||
42_i32 //~^ ERROR can't compare `i32` with `Foo`
|
||||
42_i32 //[current]~^ ERROR can't compare `i32` with `Foo`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -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`.
|
@ -1,4 +1,6 @@
|
||||
// check-pass
|
||||
// revisions: current next
|
||||
//[next] compile-flags: -Znext-solver
|
||||
//[current] check-pass
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
#![allow(dead_code)]
|
||||
@ -17,9 +19,11 @@ struct Blah {
|
||||
impl Blah {
|
||||
fn new() -> Blah {
|
||||
Blah { my_foo: make_foo(), my_u8: 12 }
|
||||
//[next]~^ ERROR type annotations needed: cannot satisfy `Foo == _`
|
||||
}
|
||||
fn into_inner(self) -> (Foo, u8, Foo) {
|
||||
(self.my_foo, self.my_u8, make_foo())
|
||||
//[next]~^ ERROR type annotations needed: cannot satisfy `Foo == _`
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
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;
|
||||
| - 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
|
||||
|
||||
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;
|
||||
| - move occurs because `y` has type `Foo`, which does not implement the `Copy` trait
|
@ -1,3 +1,7 @@
|
||||
// revisions: current next
|
||||
//[next] compile-flags: -Znext-solver
|
||||
//[next] check-pass
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
@ -13,8 +17,8 @@ fn foo1() -> (u32, Foo) {
|
||||
fn foo2() -> (u32, Foo) {
|
||||
let x: Foo = 22_u32;
|
||||
let y: Foo = x;
|
||||
same_type((x, y)); //~ ERROR use of moved value
|
||||
(y, todo!()) //~ ERROR use of moved value
|
||||
same_type((x, y)); //[current]~ ERROR use of moved value
|
||||
(y, todo!()) //[current]~ ERROR use of moved value
|
||||
}
|
||||
|
||||
fn same_type<T>(x: (T, T)) {}
|
||||
|
Loading…
Reference in New Issue
Block a user