e.span,
seg,
ParamMode::Optional,
- 0,
ParenthesizedGenericArgs::Err,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
));
let e = e.as_ref().map(|x| self.lower_expr(x));
hir::ExprKind::Ret(e)
}
+ ExprKind::Yeet(ref sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()),
ExprKind::InlineAsm(ref asm) => {
hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
}
}
/// Desugar `<expr>.await` into:
- /// ```rust
+ /// ```ignore (pseudo-rust)
/// match ::std::future::IntoFuture::into_future(<expr>) {
/// mut __awaitee => loop {
/// match unsafe { ::std::future::Future::poll(
None
}
+ /// If the given expression is a path to a unit struct, returns that path.
+ /// It is not a complete check, but just tries to reject most paths early
+ /// if they are not unit structs.
+ /// Type checking will take care of the full validation later.
+ fn extract_unit_struct_path<'a>(
+ &mut self,
+ expr: &'a Expr,
+ ) -> Option<(&'a Option<QSelf>, &'a Path)> {
+ if let ExprKind::Path(qself, path) = &expr.kind {
+ // Does the path resolve to something disallowed in a unit struct/variant pattern?
+ if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
+ if partial_res.unresolved_segments() == 0
+ && !partial_res.base_res().expected_in_unit_struct_pat()
+ {
+ return None;
+ }
+ }
+ return Some((qself, path));
+ }
+ None
+ }
+
/// Convert the LHS of a destructuring assignment to a pattern.
/// Each sub-assignment is recorded in `assignments`.
fn destructure_assign(
return self.pat_without_dbm(lhs.span, tuple_struct_pat);
}
}
+ // Unit structs and enum variants.
+ ExprKind::Path(..) => {
+ if let Some((qself, path)) = self.extract_unit_struct_path(lhs) {
+ let qpath = self.lower_qpath(
+ lhs.id,
+ qself,
+ path,
+ ParamMode::Optional,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ );
+ // Destructure like a unit struct.
+ let unit_struct_pat = hir::PatKind::Path(qpath);
+ return self.pat_without_dbm(lhs.span, unit_struct_pat);
+ }
+ }
// Structs.
ExprKind::Struct(se) => {
let field_pats = self.arena.alloc_from_iter(se.fields.iter().map(|f| {
}
/// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into:
- /// ```rust
+ /// ```ignore (pseudo-rust)
/// {
/// let result = match IntoIterator::into_iter(<head>) {
/// mut iter => {
}
/// Desugar `ExprKind::Try` from: `<expr>?` into:
- /// ```rust
+ /// ```ignore (pseudo-rust)
/// match Try::branch(<expr>) {
/// ControlFlow::Continue(val) => #[allow(unreachable_code)] val,,
/// ControlFlow::Break(residual) =>
)
}
+ /// Desugar `ExprKind::Yeet` from: `do yeet <expr>` into:
+ /// ```rust
+ /// // If there is an enclosing `try {...}`:
+ /// break 'catch_target FromResidual::from_residual(Yeet(residual)),
+ /// // Otherwise:
+ /// return FromResidual::from_residual(Yeet(residual)),
+ /// ```
+ /// But to simplify this, there's a `from_yeet` lang item function which
+ /// handles the combined `FromResidual::from_residual(Yeet(residual))`.
+ fn lower_expr_yeet(&mut self, span: Span, sub_expr: Option<&Expr>) -> hir::ExprKind<'hir> {
+ // The expression (if present) or `()` otherwise.
+ let (yeeted_span, yeeted_expr) = if let Some(sub_expr) = sub_expr {
+ (sub_expr.span, self.lower_expr(sub_expr))
+ } else {
+ (self.mark_span_with_reason(DesugaringKind::YeetExpr, span, None), self.expr_unit(span))
+ };
+
+ let unstable_span = self.mark_span_with_reason(
+ DesugaringKind::YeetExpr,
+ span,
+ self.allow_try_trait.clone(),
+ );
+
+ let from_yeet_expr = self.wrap_in_try_constructor(
+ hir::LangItem::TryTraitFromYeet,
+ unstable_span,
+ yeeted_expr,
+ yeeted_span,
+ );
+
+ if let Some(catch_node) = self.catch_scope {
+ let target_id = Ok(self.lower_node_id(catch_node));
+ hir::ExprKind::Break(hir::Destination { label: None, target_id }, Some(from_yeet_expr))
+ } else {
+ hir::ExprKind::Ret(Some(from_yeet_expr))
+ }
+ }
+
// =========================================================================
// Helper methods for building HIR.
// =========================================================================