about summary refs log tree commit diff
diff options
context:
space:
mode:
authorhkalbasi <hamidrezakalbasi@protonmail.com>2023-03-18 02:06:36 +0330
committerhkalbasi <hamidrezakalbasi@protonmail.com>2023-03-18 02:06:36 +0330
commit453ae2e00e2f3bcd96a2fa78626296e14641dae8 (patch)
tree930591c29b66657e828fd0519b8483fc49b5a8ed
parent9ad83deeccd8cb3d375b5558eb7e3d339b1a4e0b (diff)
downloadrust-453ae2e00e2f3bcd96a2fa78626296e14641dae8.tar.gz
rust-453ae2e00e2f3bcd96a2fa78626296e14641dae8.zip
Support range MIR lowering
-rw-r--r--crates/hir-ty/src/consteval/tests.rs12
-rw-r--r--crates/hir-ty/src/infer/unify.rs9
-rw-r--r--crates/hir-ty/src/mir/lower.rs48
-rw-r--r--crates/hir-ty/src/traits.rs4
4 files changed, 65 insertions, 8 deletions
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 944912b6c26..97c8d62860c 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -562,6 +562,18 @@ fn for_loops() {
 }
 
 #[test]
+fn ranges() {
+    check_number(
+        r#"
+    //- minicore: range
+    const GOAL: i32 = (1..2).start + (20..10).end + (100..=200).start + (2000..=1000).end
+        + (10000..).start + (..100000).end + (..=1000000).end;
+        "#,
+        1111111,
+    );
+}
+
+#[test]
 fn recursion() {
     check_number(
         r#"
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index 2a07dd708c2..0e516b9399a 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -633,7 +633,10 @@ impl<'a> InferenceTable<'a> {
     ) -> Option<(Option<FnTrait>, Vec<Ty>, Ty)> {
         match ty.callable_sig(self.db) {
             Some(sig) => Some((None, sig.params().to_vec(), sig.ret().clone())),
-            None => self.callable_sig_from_fn_trait(ty, num_args),
+            None => {
+                let (f, args_ty, return_ty) = self.callable_sig_from_fn_trait(ty, num_args)?;
+                Some((Some(f), args_ty, return_ty))
+            }
         }
     }
 
@@ -641,7 +644,7 @@ impl<'a> InferenceTable<'a> {
         &mut self,
         ty: &Ty,
         num_args: usize,
-    ) -> Option<(Option<FnTrait>, Vec<Ty>, Ty)> {
+    ) -> Option<(FnTrait, Vec<Ty>, Ty)> {
         let krate = self.trait_env.krate;
         let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?;
         let trait_data = self.db.trait_data(fn_once_trait);
@@ -693,7 +696,7 @@ impl<'a> InferenceTable<'a> {
                 };
                 let canonical = self.canonicalize(obligation.clone());
                 if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() {
-                    return Some((Some(fn_x), arg_tys, return_ty));
+                    return Some((fn_x, arg_tys, return_ty));
                 }
             }
             unreachable!("It should at least implement FnOnce at this point");
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 04175fb4d95..4b43e44a8ec 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -14,7 +14,7 @@ use hir_def::{
     layout::LayoutError,
     path::Path,
     resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
-    DefWithBodyId, EnumVariantId, HasModule, ItemContainerId, LocalFieldId, TraitId,
+    AdtId, DefWithBodyId, EnumVariantId, HasModule, ItemContainerId, LocalFieldId, TraitId,
 };
 use hir_expand::name::Name;
 use la_arena::ArenaMap;
@@ -643,7 +643,7 @@ impl MirLowerCtx<'_> {
                                             },
                                         }
                                     }).collect(),
-                                    None => operands.into_iter().map(|x| x).collect::<Option<_>>().ok_or(
+                                    None => operands.into_iter().collect::<Option<_>>().ok_or(
                                         MirLowerError::TypeError("missing field in record literal"),
                                     )?,
                                 },
@@ -761,7 +761,49 @@ impl MirLowerCtx<'_> {
                 );
                 Ok(Some(current))
             }
-            Expr::Range { .. } => not_supported!("range"),
+            &Expr::Range { lhs, rhs, range_type: _ } => {
+                let ty = self.expr_ty(expr_id);
+                let Some((adt, subst)) = ty.as_adt() else {
+                    return Err(MirLowerError::TypeError("Range type is not adt"));
+                };
+                let AdtId::StructId(st) = adt else {
+                    return Err(MirLowerError::TypeError("Range type is not struct"));
+                };
+                let mut lp = None;
+                let mut rp = None;
+                if let Some(x) = lhs {
+                    let Some((o, c)) = self.lower_expr_to_some_operand(x, current)? else {
+                        return Ok(None);
+                    };
+                    lp = Some(o);
+                    current = c;
+                }
+                if let Some(x) = rhs {
+                    let Some((o, c)) = self.lower_expr_to_some_operand(x, current)? else {
+                        return Ok(None);
+                    };
+                    rp = Some(o);
+                    current = c;
+                }
+                self.push_assignment(
+                    current,
+                    place,
+                    Rvalue::Aggregate(
+                        AggregateKind::Adt(st.into(), subst.clone()),
+                        self.db.struct_data(st).variant_data.fields().iter().map(|x| {
+                            let o = match x.1.name.as_str() {
+                                Some("start") => lp.take(),
+                                Some("end") => rp.take(),
+                                Some("exhausted") => Some(Operand::from_bytes(vec![0], TyBuilder::bool())),
+                                _ => None,
+                            };
+                            o.ok_or(MirLowerError::UnresolvedField)
+                        }).collect::<Result<_>>()?,
+                    ),
+                    expr_id.into(),
+                );
+                Ok(Some(current))
+            },
             Expr::Closure { .. } => not_supported!("closure"),
             Expr::Tuple { exprs, is_assignee_expr: _ } => {
                 let Some(values) = exprs
diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs
index aebf59f3152..e7fffc4cc7d 100644
--- a/crates/hir-ty/src/traits.rs
+++ b/crates/hir-ty/src/traits.rs
@@ -188,7 +188,7 @@ impl FnTrait {
         }
     }
 
-    pub fn method_name(&self) -> Name {
+    pub fn method_name(self) -> Name {
         match self {
             FnTrait::FnOnce => name!(call_once),
             FnTrait::FnMut => name!(call_mut),
@@ -196,7 +196,7 @@ impl FnTrait {
         }
     }
 
-    pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
+    pub fn get_id(self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
         let target = db.lang_item(krate, self.lang_item())?;
         match target {
             LangItemTarget::Trait(t) => Some(t),