use alias-relate to structurally normalize in the solver
This commit is contained in:
parent
bbe2f6c0b2
commit
3e3e207ad7
16 changed files with 136 additions and 119 deletions
|
@ -304,6 +304,8 @@ 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();
|
let _ = fcx.infcx.take_opaque_types();
|
||||||
|
|
||||||
// Consistency check our TypeckResults instance can hold all ItemLocalIds
|
// Consistency check our TypeckResults instance can hold all ItemLocalIds
|
||||||
|
|
|
@ -564,6 +564,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
||||||
fn visit_opaque_types(&mut self) {
|
fn visit_opaque_types(&mut self) {
|
||||||
// We clone the opaques instead of stealing them here as they are still used for
|
// We clone the opaques instead of stealing them here as they are still used for
|
||||||
// normalization in the next generation trait solver.
|
// 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();
|
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);
|
||||||
|
|
|
@ -21,10 +21,9 @@
|
||||||
//! `NormalizesTo` goal, at which point the opaque is actually defined.
|
//! `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)]
|
||||||
|
@ -79,7 +78,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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,
|
||||||
|
@ -88,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()) {
|
||||||
|
@ -108,4 +104,35 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_normalize_ty_recur(
|
||||||
|
&mut self,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
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() },
|
||||||
|
);
|
||||||
|
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 @@ 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,14 +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::ty::{self, Ty, TyCtxt, UniverseIndex};
|
use rustc_middle::ty::{self, AliasRelationDirection, Ty, TyCtxt, UniverseIndex};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
|
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
|
||||||
};
|
};
|
||||||
|
@ -266,49 +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(_, 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,
|
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);
|
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),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
|
@ -581,11 +581,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));
|
||||||
|
|
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
|
// 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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
--> $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`.
|
||||||
|
|
|
@ -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`.
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue