@@ -178,16 +178,6 @@ TypeCheckExpr::visit (HIR::CallExpr &expr)
178
178
{
179
179
TyTy::BaseType *function_tyty = TypeCheckExpr::Resolve (expr.get_fnexpr ());
180
180
181
- bool valid_tyty = function_tyty->get_kind () == TyTy::TypeKind::ADT
182
- || function_tyty->get_kind () == TyTy::TypeKind::FNDEF
183
- || function_tyty->get_kind () == TyTy::TypeKind::FNPTR;
184
- if (!valid_tyty)
185
- {
186
- rust_error_at (expr.get_locus (),
187
- " Failed to resolve expression of function call" );
188
- return ;
189
- }
190
-
191
181
rust_debug_loc (expr.get_locus (), " resolved_call_expr to: {%s}" ,
192
182
function_tyty->get_name ().c_str ());
193
183
@@ -214,6 +204,24 @@ TypeCheckExpr::visit (HIR::CallExpr &expr)
214
204
rust_assert (adt->number_of_variants () == 1 );
215
205
variant = *adt->get_variants ().at (0 );
216
206
}
207
+
208
+ infered
209
+ = TyTy::TypeCheckCallExpr::go (function_tyty, expr, variant, context);
210
+ return ;
211
+ }
212
+
213
+ bool resolved_fn_trait_call
214
+ = resolve_fn_trait_call (expr, function_tyty, &infered);
215
+ if (resolved_fn_trait_call)
216
+ return ;
217
+
218
+ bool valid_tyty = function_tyty->get_kind () == TyTy::TypeKind::FNDEF
219
+ || function_tyty->get_kind () == TyTy::TypeKind::FNPTR;
220
+ if (!valid_tyty)
221
+ {
222
+ rust_error_at (expr.get_locus (),
223
+ " Failed to resolve expression of function call" );
224
+ return ;
217
225
}
218
226
219
227
infered = TyTy::TypeCheckCallExpr::go (function_tyty, expr, variant, context);
@@ -1422,7 +1430,123 @@ TypeCheckExpr::visit (HIR::MatchExpr &expr)
1422
1430
void
1423
1431
TypeCheckExpr::visit (HIR::ClosureExpr &expr)
1424
1432
{
1425
- gcc_unreachable ();
1433
+ TypeCheckContextItem ¤t_context = context->peek_context ();
1434
+ TyTy::FnType *current_context_fndecl = current_context.get_context_type ();
1435
+
1436
+ HirId ref = expr.get_mappings ().get_hirid ();
1437
+ DefId id = expr.get_mappings ().get_defid ();
1438
+ RustIdent ident{current_context_fndecl->get_ident ().path , expr.get_locus ()};
1439
+
1440
+ // get from parent context
1441
+ std::vector<TyTy::SubstitutionParamMapping> subst_refs
1442
+ = current_context_fndecl->clone_substs ();
1443
+
1444
+ std::vector<TyTy::TyVar> parameter_types;
1445
+ for (auto &p : expr.get_params ())
1446
+ {
1447
+ if (p.has_type_given ())
1448
+ {
1449
+ TyTy::BaseType *param_tyty
1450
+ = TypeCheckType::Resolve (p.get_type ().get ());
1451
+ TyTy::TyVar param_ty (param_tyty->get_ref ());
1452
+ parameter_types.push_back (param_ty);
1453
+
1454
+ TypeCheckPattern::Resolve (p.get_pattern ().get (),
1455
+ param_ty.get_tyty ());
1456
+ }
1457
+ else
1458
+ {
1459
+ TyTy::TyVar param_ty
1460
+ = TyTy::TyVar::get_implicit_infer_var (p.get_locus ());
1461
+ parameter_types.push_back (param_ty);
1462
+
1463
+ TypeCheckPattern::Resolve (p.get_pattern ().get (),
1464
+ param_ty.get_tyty ());
1465
+ }
1466
+ }
1467
+
1468
+ // we generate an implicit hirid for the closure args
1469
+ HirId implicit_args_id = mappings->get_next_hir_id ();
1470
+ TyTy::TupleType *closure_args
1471
+ = new TyTy::TupleType (implicit_args_id, expr.get_locus (),
1472
+ parameter_types);
1473
+ context->insert_implicit_type (closure_args);
1474
+
1475
+ Location result_type_locus = expr.has_return_type ()
1476
+ ? expr.get_return_type ()->get_locus ()
1477
+ : expr.get_locus ();
1478
+ TyTy::TyVar result_type
1479
+ = expr.has_return_type ()
1480
+ ? TyTy::TyVar (
1481
+ TypeCheckType::Resolve (expr.get_return_type ().get ())->get_ref ())
1482
+ : TyTy::TyVar::get_implicit_infer_var (expr.get_locus ());
1483
+
1484
+ // resolve the block
1485
+ Location closure_expr_locus = expr.get_expr ()->get_locus ();
1486
+ TyTy::BaseType *closure_expr_ty
1487
+ = TypeCheckExpr::Resolve (expr.get_expr ().get ());
1488
+ coercion_site (expr.get_mappings ().get_hirid (),
1489
+ TyTy::TyWithLocation (result_type.get_tyty (),
1490
+ result_type_locus),
1491
+ TyTy::TyWithLocation (closure_expr_ty, closure_expr_locus),
1492
+ expr.get_locus ());
1493
+
1494
+ // generate the closure type
1495
+ infered = new TyTy::ClosureType (ref, id, ident, closure_args, result_type,
1496
+ subst_refs);
1497
+
1498
+ // FIXME
1499
+ // all closures automatically inherit the appropriate fn trait. Lets just
1500
+ // assume FnOnce for now. I think this is based on the return type of the
1501
+ // closure
1502
+
1503
+ Analysis::RustLangItem::ItemType lang_item_type
1504
+ = Analysis::RustLangItem::ItemType::FN_ONCE;
1505
+ DefId respective_lang_item_id = UNKNOWN_DEFID;
1506
+ bool lang_item_defined
1507
+ = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id);
1508
+ if (!lang_item_defined)
1509
+ {
1510
+ // FIXME
1511
+ // we need to have a unified way or error'ing when we are missing lang
1512
+ // items that is useful
1513
+ rust_fatal_error (
1514
+ expr.get_locus (), " unable to find lang item: %<%s%>" ,
1515
+ Analysis::RustLangItem::ToString (lang_item_type).c_str ());
1516
+ }
1517
+ rust_assert (lang_item_defined);
1518
+
1519
+ // these lang items are always traits
1520
+ HIR::Item *item = mappings->lookup_defid (respective_lang_item_id);
1521
+ rust_assert (item->get_item_kind () == HIR::Item::ItemKind::Trait);
1522
+ HIR::Trait *trait_item = static_cast <HIR::Trait *> (item);
1523
+
1524
+ TraitReference *trait = TraitResolver::Resolve (*trait_item);
1525
+ rust_assert (!trait->is_error ());
1526
+
1527
+ TyTy::TypeBoundPredicate predicate (*trait, expr.get_locus ());
1528
+
1529
+ // resolve the trait bound where the <(Args)> are the parameter tuple type
1530
+ HIR::GenericArgs args = HIR::GenericArgs::create_empty (expr.get_locus ());
1531
+
1532
+ // lets generate an implicit Type so that it resolves to the implict tuple
1533
+ // type we have created
1534
+ auto crate_num = mappings->get_current_crate ();
1535
+ Analysis::NodeMapping mapping (crate_num, expr.get_mappings ().get_nodeid (),
1536
+ implicit_args_id, UNKNOWN_LOCAL_DEFID);
1537
+ HIR::TupleType *implicit_tuple
1538
+ = new HIR::TupleType (mapping,
1539
+ {} // we dont need to fill this out because it will
1540
+ // auto resolve because the hir id's match
1541
+ ,
1542
+ expr.get_locus ());
1543
+ args.get_type_args ().push_back (std::unique_ptr<HIR::Type> (implicit_tuple));
1544
+
1545
+ // apply the arguments
1546
+ predicate.apply_generic_arguments (&args);
1547
+
1548
+ // finally inherit the trait bound
1549
+ infered->inherit_bounds ({predicate});
1426
1550
}
1427
1551
1428
1552
bool
@@ -1630,6 +1754,168 @@ TypeCheckExpr::resolve_operator_overload (
1630
1754
return true ;
1631
1755
}
1632
1756
1757
+ HIR::PathIdentSegment
1758
+ TypeCheckExpr::resolve_possible_fn_trait_call_method_name (
1759
+ const TyTy::BaseType &receiver)
1760
+ {
1761
+ // Question
1762
+ // do we need to probe possible bounds here? I think not, i think when we
1763
+ // support Fn traits they are explicitly specified
1764
+
1765
+ // FIXME
1766
+ // the logic to map the FnTrait to their respective call trait-item is
1767
+ // duplicated over in the backend/rust-compile-expr.cc
1768
+ for (const auto &bound : receiver.get_specified_bounds ())
1769
+ {
1770
+ bool found_fn = bound.get_name ().compare (" Fn" ) == 0 ;
1771
+ bool found_fn_mut = bound.get_name ().compare (" FnMut" ) == 0 ;
1772
+ bool found_fn_once = bound.get_name ().compare (" FnOnce" ) == 0 ;
1773
+
1774
+ if (found_fn)
1775
+ {
1776
+ return HIR::PathIdentSegment (" call" );
1777
+ }
1778
+ else if (found_fn_mut)
1779
+ {
1780
+ return HIR::PathIdentSegment (" call_mut" );
1781
+ }
1782
+ else if (found_fn_once)
1783
+ {
1784
+ return HIR::PathIdentSegment (" call_once" );
1785
+ }
1786
+ }
1787
+
1788
+ // nothing
1789
+ return HIR::PathIdentSegment (" " );
1790
+ }
1791
+
1792
+ bool
1793
+ TypeCheckExpr::resolve_fn_trait_call (HIR::CallExpr &expr,
1794
+ TyTy::BaseType *receiver_tyty,
1795
+ TyTy::BaseType **result)
1796
+ {
1797
+ // we turn this into a method call expr
1798
+ HIR::PathIdentSegment method_name
1799
+ = resolve_possible_fn_trait_call_method_name (*receiver_tyty);
1800
+ if (method_name.is_error ())
1801
+ return false ;
1802
+
1803
+ auto candidates = MethodResolver::Probe (receiver_tyty, method_name);
1804
+ if (candidates.empty ())
1805
+ return false ;
1806
+
1807
+ if (candidates.size () > 1 )
1808
+ {
1809
+ RichLocation r (expr.get_locus ());
1810
+ for (auto &c : candidates)
1811
+ r.add_range (c.candidate .locus );
1812
+
1813
+ rust_error_at (
1814
+ r, " multiple candidates found for function trait method call %<%s%>" ,
1815
+ method_name.as_string ().c_str ());
1816
+ return false ;
1817
+ }
1818
+
1819
+ if (receiver_tyty->get_kind () == TyTy::TypeKind::CLOSURE)
1820
+ {
1821
+ const TyTy::ClosureType &closure
1822
+ = static_cast <TyTy::ClosureType &> (*receiver_tyty);
1823
+ closure.setup_fn_once_output ();
1824
+ }
1825
+
1826
+ auto candidate = *candidates.begin ();
1827
+ rust_debug_loc (expr.get_locus (),
1828
+ " resolved call-expr to fn trait: {%u} {%s}" ,
1829
+ candidate.candidate .ty ->get_ref (),
1830
+ candidate.candidate .ty ->debug_str ().c_str ());
1831
+
1832
+ // Get the adjusted self
1833
+ Adjuster adj (receiver_tyty);
1834
+ TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments );
1835
+
1836
+ // store the adjustments for code-generation to know what to do which must be
1837
+ // stored onto the receiver to so as we don't trigger duplicate deref mappings
1838
+ // ICE when an argument is a method call
1839
+ HirId autoderef_mappings_id = expr.get_mappings ().get_hirid ();
1840
+ context->insert_autoderef_mappings (autoderef_mappings_id,
1841
+ std::move (candidate.adjustments ));
1842
+ context->insert_receiver (expr.get_mappings ().get_hirid (), receiver_tyty);
1843
+
1844
+ PathProbeCandidate &resolved_candidate = candidate.candidate ;
1845
+ TyTy::BaseType *lookup_tyty = candidate.candidate .ty ;
1846
+ NodeId resolved_node_id
1847
+ = resolved_candidate.is_impl_candidate ()
1848
+ ? resolved_candidate.item .impl .impl_item ->get_impl_mappings ()
1849
+ .get_nodeid ()
1850
+ : resolved_candidate.item .trait .item_ref ->get_mappings ().get_nodeid ();
1851
+
1852
+ if (lookup_tyty->get_kind () != TyTy::TypeKind::FNDEF)
1853
+ {
1854
+ RichLocation r (expr.get_locus ());
1855
+ r.add_range (resolved_candidate.locus );
1856
+ rust_error_at (r, " associated impl item is not a method" );
1857
+ return false ;
1858
+ }
1859
+
1860
+ TyTy::BaseType *lookup = lookup_tyty;
1861
+ TyTy::FnType *fn = static_cast <TyTy::FnType *> (lookup);
1862
+ if (!fn->is_method ())
1863
+ {
1864
+ RichLocation r (expr.get_locus ());
1865
+ r.add_range (resolved_candidate.locus );
1866
+ rust_error_at (r, " associated function is not a method" );
1867
+ return false ;
1868
+ }
1869
+
1870
+ // fn traits only support tuple argument passing so we need to implicitly set
1871
+ // this up to get the same type checking we get in the rest of the pipeline
1872
+
1873
+ std::vector<TyTy::TyVar> call_args;
1874
+ for (auto &arg : expr.get_arguments ())
1875
+ {
1876
+ TyTy::BaseType *a = TypeCheckExpr::Resolve (arg.get ());
1877
+ call_args.push_back (TyTy::TyVar (a->get_ref ()));
1878
+ }
1879
+
1880
+ // crate implicit tuple
1881
+ HirId implicit_arg_id = mappings->get_next_hir_id ();
1882
+ Analysis::NodeMapping mapping (mappings->get_current_crate (), UNKNOWN_NODEID,
1883
+ implicit_arg_id, UNKNOWN_LOCAL_DEFID);
1884
+
1885
+ TyTy::TupleType *tuple
1886
+ = new TyTy::TupleType (implicit_arg_id, expr.get_locus (), call_args);
1887
+ context->insert_implicit_type (implicit_arg_id, tuple);
1888
+
1889
+ std::vector<TyTy::Argument> args;
1890
+ TyTy::Argument a (mapping, tuple,
1891
+ expr.get_locus () /* FIXME is there a better location*/ );
1892
+ args.push_back (std::move (a));
1893
+
1894
+ TyTy::BaseType *function_ret_tyty
1895
+ = TyTy::TypeCheckMethodCallExpr::go (fn, expr.get_mappings (), args,
1896
+ expr.get_locus (), expr.get_locus (),
1897
+ adjusted_self, context);
1898
+ if (function_ret_tyty == nullptr
1899
+ || function_ret_tyty->get_kind () == TyTy::TypeKind::ERROR)
1900
+ {
1901
+ rust_error_at (expr.get_locus (),
1902
+ " failed check fn trait call-expr MethodCallExpr" );
1903
+ return false ;
1904
+ }
1905
+
1906
+ // store the expected fntype
1907
+ context->insert_operator_overload (expr.get_mappings ().get_hirid (), fn);
1908
+
1909
+ // set up the resolved name on the path
1910
+ resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (),
1911
+ resolved_node_id);
1912
+
1913
+ // return the result of the function back
1914
+ *result = function_ret_tyty;
1915
+
1916
+ return true ;
1917
+ }
1918
+
1633
1919
bool
1634
1920
TypeCheckExpr::validate_arithmetic_type (
1635
1921
const TyTy::BaseType *tyty, HIR::ArithmeticOrLogicalExpr::ExprType expr_type)
0 commit comments