Skip to content

Commit 97b357e

Browse files
committed
Auto merge of rust-lang#13433 - rust-lang:revert-13354-try-stuff, r=Veykril
Revert "feat: Diagnose some incorrect usages of the question mark operator" Reverts rust-lang/rust-analyzer#13354 It seems like we are getting stuck with inference variables here, not just placeholders and errors so there is probably more wrong here that I don't understand. Reverting seems like the best solution right now as I don't have the time to look into this this week.
2 parents 4d4c05d + 8047512 commit 97b357e

File tree

13 files changed

+125
-289
lines changed

13 files changed

+125
-289
lines changed

crates/hir-expand/src/mod_path.rs

-1
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,6 @@ macro_rules! __known_path {
259259
(core::future::Future) => {};
260260
(core::future::IntoFuture) => {};
261261
(core::ops::Try) => {};
262-
(core::ops::FromResidual) => {};
263262
($path:path) => {
264263
compile_error!("Please register your known path in the path module")
265264
};

crates/hir-expand/src/name.rs

-2
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,6 @@ pub mod known {
279279
RangeToInclusive,
280280
RangeTo,
281281
Range,
282-
Residual,
283-
FromResidual,
284282
Neg,
285283
Not,
286284
None,

crates/hir-ty/src/infer.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,7 @@ pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
190190
pub enum InferenceDiagnostic {
191191
NoSuchField { expr: ExprId },
192192
BreakOutsideOfLoop { expr: ExprId, is_break: bool },
193-
IncorrectTryTarget { expr: ExprId },
194193
MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize },
195-
DoesNotImplement { expr: ExprId, trait_: TraitId, ty: Ty },
196194
}
197195

198196
/// A mismatch between an expected and an inferred type.
@@ -907,6 +905,17 @@ impl<'a> InferenceContext<'a> {
907905
self.db.trait_data(trait_).associated_type_by_name(&name![Item])
908906
}
909907

908+
fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> {
909+
// FIXME resolve via lang_item once try v2 is stable
910+
let path = path![core::ops::Try];
911+
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
912+
let trait_data = self.db.trait_data(trait_);
913+
trait_data
914+
// FIXME remove once try v2 is stable
915+
.associated_type_by_name(&name![Ok])
916+
.or_else(|| trait_data.associated_type_by_name(&name![Output]))
917+
}
918+
910919
fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
911920
let trait_ = self.resolve_lang_item(name![neg])?.as_trait()?;
912921
self.db.trait_data(trait_).associated_type_by_name(&name![Output])

crates/hir-ty/src/infer/expr.rs

+8-91
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,24 @@ use hir_def::{
1919
resolver::resolver_for_expr,
2020
ConstParamId, FieldId, ItemContainerId, Lookup,
2121
};
22-
use hir_expand::{name, name::Name};
22+
use hir_expand::name::Name;
2323
use stdx::always;
2424
use syntax::ast::RangeOp;
2525

2626
use crate::{
2727
autoderef::{self, Autoderef},
2828
consteval,
29-
infer::{coerce::CoerceMany, find_continuable, path, BreakableKind},
29+
infer::{coerce::CoerceMany, find_continuable, BreakableKind},
3030
lower::{
3131
const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
3232
},
3333
mapping::{from_chalk, ToChalk},
3434
method_resolution::{self, lang_names_for_bin_op, VisibleFromModule},
3535
primitive::{self, UintTy},
36-
static_lifetime, to_assoc_type_id, to_chalk_trait_id,
36+
static_lifetime, to_chalk_trait_id,
3737
utils::{generics, Generics},
38-
AdtId, AliasEq, AliasTy, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner,
39-
ProjectionTy, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
38+
AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar,
39+
Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
4040
};
4141

4242
use super::{
@@ -564,29 +564,9 @@ impl<'a> InferenceContext<'a> {
564564
let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
565565
self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
566566
}
567-
&Expr::Try { expr } => {
568-
let inner_ty = self.infer_expr_inner(expr, &Expectation::none());
569-
match self.resolve_try_impl_for(inner_ty.clone()) {
570-
Some((_, Some((output, residual)))) => {
571-
if let Some((_trait, false)) =
572-
self.implements_from_residual(self.return_ty.clone(), residual)
573-
{
574-
self.push_diagnostic(InferenceDiagnostic::IncorrectTryTarget {
575-
expr: tgt_expr,
576-
});
577-
}
578-
output
579-
}
580-
Some((trait_, None)) => {
581-
self.push_diagnostic(InferenceDiagnostic::DoesNotImplement {
582-
expr,
583-
trait_,
584-
ty: inner_ty,
585-
});
586-
self.err_ty()
587-
}
588-
None => self.err_ty(),
589-
}
567+
Expr::Try { expr } => {
568+
let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
569+
self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok())
590570
}
591571
Expr::Cast { expr, type_ref } => {
592572
// FIXME: propagate the "castable to" expectation (and find a test case that shows this is necessary)
@@ -1550,67 +1530,4 @@ impl<'a> InferenceContext<'a> {
15501530
let ctx = self.breakables.pop().expect("breakable stack broken");
15511531
(ctx.may_break.then(|| ctx.coerce.complete()), res)
15521532
}
1553-
1554-
/// Check whether `ty` implements `FromResidual<r>`
1555-
fn implements_from_residual(&mut self, ty: Ty, r: Ty) -> Option<(hir_def::TraitId, bool)> {
1556-
let from_residual_trait = self
1557-
.resolver
1558-
.resolve_known_trait(self.db.upcast(), &(super::path![core::ops::FromResidual]))?;
1559-
let r = GenericArgData::Ty(r).intern(Interner);
1560-
let b = TyBuilder::trait_ref(self.db, from_residual_trait);
1561-
if b.remaining() != 2 {
1562-
return Some((from_residual_trait, false));
1563-
}
1564-
let trait_ref = b.push(ty).push(r).build();
1565-
Some((from_residual_trait, self.table.try_obligation(trait_ref.cast(Interner)).is_some()))
1566-
}
1567-
1568-
fn resolve_try_impl_for(&mut self, ty: Ty) -> Option<(hir_def::TraitId, Option<(Ty, Ty)>)> {
1569-
let path = path![core::ops::Try];
1570-
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
1571-
1572-
let trait_ref = TyBuilder::trait_ref(self.db, trait_).push(ty).build();
1573-
let substitution = trait_ref.substitution.clone();
1574-
self.push_obligation(trait_ref.clone().cast(Interner));
1575-
1576-
let trait_data = self.db.trait_data(trait_);
1577-
let output = trait_data.associated_type_by_name(&name![Output]);
1578-
let residual = trait_data.associated_type_by_name(&name![Residual]);
1579-
1580-
let output_ty = match output {
1581-
Some(output) => {
1582-
let output_ty = self.table.new_type_var();
1583-
let alias_eq = AliasEq {
1584-
alias: AliasTy::Projection(ProjectionTy {
1585-
associated_ty_id: to_assoc_type_id(output),
1586-
substitution: substitution.clone(),
1587-
}),
1588-
ty: output_ty.clone(),
1589-
};
1590-
self.push_obligation(alias_eq.cast(Interner));
1591-
output_ty
1592-
}
1593-
None => self.err_ty(),
1594-
};
1595-
let residual_ty = match residual {
1596-
Some(residual) => {
1597-
let residual_ty = self.table.new_type_var();
1598-
let alias_eq = AliasEq {
1599-
alias: AliasTy::Projection(ProjectionTy {
1600-
associated_ty_id: to_assoc_type_id(residual),
1601-
substitution,
1602-
}),
1603-
ty: residual_ty.clone(),
1604-
};
1605-
self.push_obligation(alias_eq.cast(Interner));
1606-
residual_ty
1607-
}
1608-
None => self.err_ty(),
1609-
};
1610-
// FIXME: We are doing the work twice here I think?
1611-
Some((
1612-
trait_,
1613-
self.table.try_obligation(trait_ref.cast(Interner)).map(|_| (output_ty, residual_ty)),
1614-
))
1615-
}
16161533
}

crates/hir-ty/src/method_resolution.rs

-18
Original file line numberDiff line numberDiff line change
@@ -1111,24 +1111,6 @@ pub fn resolve_indexing_op(
11111111
}
11121112
None
11131113
}
1114-
/// Returns the receiver type for the try branch trait call.
1115-
pub fn resolve_branch_op(
1116-
db: &dyn HirDatabase,
1117-
env: Arc<TraitEnvironment>,
1118-
ty: Canonical<Ty>,
1119-
try_trait: TraitId,
1120-
) -> Option<ReceiverAdjustments> {
1121-
let mut table = InferenceTable::new(db, env.clone());
1122-
let ty = table.instantiate_canonical(ty);
1123-
let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty);
1124-
for (ty, adj) in deref_chain.into_iter().zip(adj) {
1125-
let goal = generic_implements_goal(db, env.clone(), try_trait, &ty);
1126-
if db.trait_solve(env.krate, goal.cast(Interner)).is_some() {
1127-
return Some(adj);
1128-
}
1129-
}
1130-
None
1131-
}
11321114

11331115
macro_rules! check_that {
11341116
($cond:expr) => {

crates/hir-ty/src/tests/traits.rs

+87-5
Original file line numberDiff line numberDiff line change
@@ -162,16 +162,98 @@ fn test() {
162162
);
163163
}
164164

165+
#[test]
166+
fn infer_try() {
167+
check_types(
168+
r#"
169+
//- /main.rs crate:main deps:core
170+
fn test() {
171+
let r: Result<i32, u64> = Result::Ok(1);
172+
let v = r?;
173+
v;
174+
} //^ i32
175+
176+
//- /core.rs crate:core
177+
pub mod ops {
178+
pub trait Try {
179+
type Ok;
180+
type Error;
181+
}
182+
}
183+
184+
pub mod result {
185+
pub enum Result<O, E> {
186+
Ok(O),
187+
Err(E)
188+
}
189+
190+
impl<O, E> crate::ops::Try for Result<O, E> {
191+
type Ok = O;
192+
type Error = E;
193+
}
194+
}
195+
196+
pub mod prelude {
197+
pub mod rust_2018 {
198+
pub use crate::{result::*, ops::*};
199+
}
200+
}
201+
"#,
202+
);
203+
}
204+
165205
#[test]
166206
fn infer_try_trait_v2() {
167207
check_types(
168208
r#"
169-
//- minicore: try
170-
fn test() -> core::ops::ControlFlow<u32, f32> {
171-
let r: core::ops::ControlFlow<u32, f32> = core::ops::ControlFlow::Continue(1.0);
209+
//- /main.rs crate:main deps:core
210+
fn test() {
211+
let r: Result<i32, u64> = Result::Ok(1);
172212
let v = r?;
173-
//^ f32
174-
r
213+
v;
214+
} //^ i32
215+
216+
//- /core.rs crate:core
217+
mod ops {
218+
mod try_trait {
219+
pub trait Try: FromResidual {
220+
type Output;
221+
type Residual;
222+
}
223+
pub trait FromResidual<R = <Self as Try>::Residual> {}
224+
}
225+
226+
pub use self::try_trait::FromResidual;
227+
pub use self::try_trait::Try;
228+
}
229+
230+
mod convert {
231+
pub trait From<T> {}
232+
impl<T> From<T> for T {}
233+
}
234+
235+
pub mod result {
236+
use crate::convert::From;
237+
use crate::ops::{Try, FromResidual};
238+
239+
pub enum Infallible {}
240+
pub enum Result<O, E> {
241+
Ok(O),
242+
Err(E)
243+
}
244+
245+
impl<O, E> Try for Result<O, E> {
246+
type Output = O;
247+
type Error = Result<Infallible, E>;
248+
}
249+
250+
impl<T, E, F: From<E>> FromResidual<Result<Infallible, E>> for Result<T, F> {}
251+
}
252+
253+
pub mod prelude {
254+
pub mod rust_2018 {
255+
pub use crate::result::*;
256+
}
175257
}
176258
"#,
177259
);

crates/hir/src/diagnostics.rs

+1-13
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use base_db::CrateId;
77
use cfg::{CfgExpr, CfgOptions};
88
use either::Either;
9-
use hir_def::{path::ModPath, TraitId};
9+
use hir_def::path::ModPath;
1010
use hir_expand::{name::Name, HirFileId, InFile};
1111
use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
1212

@@ -33,15 +33,13 @@ diagnostics![
3333
BreakOutsideOfLoop,
3434
InactiveCode,
3535
IncorrectCase,
36-
IncorrectTryExpr,
3736
InvalidDeriveTarget,
3837
MacroError,
3938
MalformedDerive,
4039
MismatchedArgCount,
4140
MissingFields,
4241
MissingMatchArms,
4342
MissingUnsafe,
44-
NotImplemented,
4543
NoSuchField,
4644
ReplaceFilterMapNextWithFindMap,
4745
TypeMismatch,
@@ -155,16 +153,6 @@ pub struct MismatchedArgCount {
155153
pub expected: usize,
156154
pub found: usize,
157155
}
158-
#[derive(Debug)]
159-
pub struct IncorrectTryExpr {
160-
pub expr: InFile<AstPtr<ast::Expr>>,
161-
}
162-
#[derive(Debug)]
163-
pub struct NotImplemented {
164-
pub expr: InFile<AstPtr<ast::Expr>>,
165-
pub trait_: TraitId,
166-
pub ty: Type,
167-
}
168156

169157
#[derive(Debug)]
170158
pub struct MissingMatchArms {

0 commit comments

Comments
 (0)