aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cargo/config2
-rw-r--r--.travis.yml4
-rw-r--r--Cargo.lock36
-rw-r--r--Cargo.toml2
-rw-r--r--README.md2
-rw-r--r--crates/ra_assists/Cargo.toml2
-rw-r--r--crates/ra_assists/src/ast_editor.rs2
-rw-r--r--crates/ra_assists/src/introduce_variable.rs9
-rw-r--r--crates/ra_assists/src/move_guard.rs4
-rw-r--r--crates/ra_assists/src/replace_if_let_with_match.rs16
-rw-r--r--crates/ra_cli/src/analysis_stats.rs40
-rw-r--r--crates/ra_fmt/src/lib.rs3
-rw-r--r--crates/ra_hir/Cargo.toml2
-rw-r--r--crates/ra_hir/src/code_model.rs49
-rw-r--r--crates/ra_hir/src/code_model/src.rs45
-rw-r--r--crates/ra_hir/src/expr.rs693
-rw-r--r--crates/ra_hir/src/expr/lower.rs630
-rw-r--r--crates/ra_hir/src/expr/scope.rs5
-rw-r--r--crates/ra_hir/src/expr/validation.rs46
-rw-r--r--crates/ra_hir/src/lib.rs10
-rw-r--r--crates/ra_hir/src/path.rs21
-rw-r--r--crates/ra_hir/src/source_binder.rs41
-rw-r--r--crates/ra_hir/src/ty.rs348
-rw-r--r--crates/ra_hir/src/ty/autoderef.rs2
-rw-r--r--crates/ra_hir/src/ty/infer.rs14
-rw-r--r--crates/ra_hir/src/ty/infer/unify.rs2
-rw-r--r--crates/ra_hir/src/ty/lower.rs86
-rw-r--r--crates/ra_hir/src/ty/tests.rs124
-rw-r--r--crates/ra_hir/src/ty/traits.rs17
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs8
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs2
-rw-r--r--crates/ra_ide_api/src/join_lines.rs2
-rw-r--r--crates/ra_ide_api/src/syntax_tree.rs91
-rw-r--r--crates/ra_lsp_server/Cargo.toml2
-rw-r--r--crates/ra_lsp_server/src/caps.rs1
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs124
-rw-r--r--crates/ra_mbe/src/subtree_parser.rs40
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs32
-rw-r--r--crates/ra_mbe/src/tests.rs31
-rw-r--r--crates/ra_mbe/src/tt_cursor.rs46
-rw-r--r--crates/ra_parser/src/grammar.rs147
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs5
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs4
-rw-r--r--crates/ra_parser/src/grammar/paths.rs2
-rw-r--r--crates/ra_parser/src/grammar/patterns.rs2
-rw-r--r--crates/ra_parser/src/grammar/types.rs2
-rw-r--r--crates/ra_parser/src/lib.rs86
-rw-r--r--crates/ra_prof/Cargo.toml2
-rw-r--r--crates/ra_syntax/src/ast/expr_extensions.rs26
-rw-r--r--crates/ra_syntax/src/ast/generated.rs9
-rw-r--r--crates/ra_syntax/src/ast/traits.rs8
-rw-r--r--crates/ra_syntax/src/grammar.ron4
-rw-r--r--crates/ra_syntax/src/lib.rs3
-rw-r--r--crates/ra_syntax/src/validation.rs2
-rw-r--r--crates/ra_syntax/src/validation/block.rs20
-rw-r--r--crates/ra_syntax/test_data/parser/err/0005_attribute_recover.txt9
-rw-r--r--crates/ra_syntax/test_data/parser/err/0007_stray_curly_in_file.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/err/0008_item_block_recovery.txt60
-rw-r--r--crates/ra_syntax/test_data/parser/err/0010_unsafe_lambda_block.txt61
-rw-r--r--crates/ra_syntax/test_data/parser/err/0014_where_no_bounds.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/err/0016_missing_semi.txt63
-rw-r--r--crates/ra_syntax/test_data/parser/err/0017_incomplete_binexpr.txt47
-rw-r--r--crates/ra_syntax/test_data/parser/err/0018_incomplete_fn.txt167
-rw-r--r--crates/ra_syntax/test_data/parser/err/0019_let_recover.txt168
-rw-r--r--crates/ra_syntax/test_data/parser/err/0020_fn_recover.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/err/0021_incomplete_param.txt9
-rw-r--r--crates/ra_syntax/test_data/parser/err/0022_bad_exprs.txt241
-rw-r--r--crates/ra_syntax/test_data/parser/err/0023_mismatched_paren.txt51
-rw-r--r--crates/ra_syntax/test_data/parser/err/0024_many_type_parens.txt440
-rw-r--r--crates/ra_syntax/test_data/parser/err/0025_nope.txt363
-rw-r--r--crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/err/0028_macro_2.0.txt365
-rw-r--r--crates/ra_syntax/test_data/parser/err/0029_field_completion.txt25
-rw-r--r--crates/ra_syntax/test_data/parser/err/0031_block_inner_attrs.txt201
-rw-r--r--crates/ra_syntax/test_data/parser/err/0032_match_arms_inner_attrs.txt359
-rw-r--r--crates/ra_syntax/test_data/parser/err/0033_match_arms_outer_attrs.txt101
-rw-r--r--crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.txt157
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0002_misplaced_label_err.txt27
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0006_unsafe_block_in_mod.txt14
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0007_async_without_semicolon.txt39
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0008_pub_expr.txt27
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.txt86
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0010_bad_tuple_index_expr.txt79
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.txt14
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0001_trait_item_list.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.txt9
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0005_function_type_params.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0006_self_param.txt35
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0008_path_part.txt169
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0009_loop_expr.txt28
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0011_field_expr.txt97
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0015_continue_expr.txt50
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0018_arb_self_types.txt14
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0019_unary_expr.txt67
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0021_impl_item_list.txt14
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0024_slice_pat.txt59
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0026_tuple_pat_fields.txt185
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0027_ref_pat.txt77
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0029_cast_expr.txt157
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0030_cond.txt365
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.txt113
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0034_break_expr.txt86
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0037_qual_paths.txt69
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0038_full_range_expr.txt35
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0040_crate_keyword_vis.txt9
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0042_call_expr.txt273
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0044_block_items.txt36
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0045_param_list_opt_patterns.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0048_path_type_with_bounds.txt14
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0053_path_expr.txt169
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0055_literal_pattern.txt131
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0056_where_clause.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0058_range_pat.txt143
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0059_match_arms_commas.txt97
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0061_record_lit.txt215
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0062_mod_contents.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.txt176
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.txt277
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.txt83
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.txt67
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0072_return_expr.txt35
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.txt103
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0075_block.txt94
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0076_function_where_clause.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0077_try_expr.txt29
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.txt39
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.txt21
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0082_ref_expr.txt87
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0085_expr_literals.txt249
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0086_function_ret_type.txt14
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0088_break_ambiguity.txt114
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0093_index_expr.txt45
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0095_placeholder_pat.txt35
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0096_no_semi_after_block.txt233
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0099_param_list.txt28
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0100_for_expr.txt48
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0102_record_field_pat_list.txt239
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0103_array_expr.txt87
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0105_block_expr.txt63
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0106_lambda_expr.txt257
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0107_method_call_expr.txt103
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0108_tuple_expr.txt55
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0109_label.txt110
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.txt59
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0112_bind_pat.txt233
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0113_nocontentexpr.txt93
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0118_match_guard.txt73
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.txt127
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.txt249
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.txt9
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0125_crate_keyword_path.txt41
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.txt69
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.txt155
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.txt87
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.txt14
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt51
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0130_let_stmt.txt181
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0130_try_block_expr.txt42
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0132_box_expr.txt157
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0134_nocontentexpr_after_item.txt104
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0137_await_expr.txt117
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0138_expression_after_block.txt109
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0139_param_outer_arg.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0142_for_range_from.txt60
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.txt197
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0005_fn_item.txt9
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0008_mod_item.txt9
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0011_outer_attribute.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0012_visibility.txt35
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0017_attr_trailing_comma.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0021_extern_fn.txt27
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0025_extern_fn_in_block.txt42
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0026_const_fn_in_block.txt40
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0027_unsafe_fn_in_block.txt62
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0028_operator_binding_power.txt349
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0029_range_forms.txt281
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0030_string_suffixes.txt105
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0032_where_for.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0033_label_break.txt409
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0034_crate_path_in_call.txt61
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0035_weird_exprs.txt3948
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0036_fully_qualified.txt29
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0038_where_pred_type.txt7
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0039_raw_fn_item.txt9
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0041_raw_keywords.txt79
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0042_ufcs_call_list.txt103
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0043_complex_assignment.txt135
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0044_let_attrs.txt121
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0045_block_inner_attrs.txt182
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0047_minus_in_inner_pattern.txt499
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0048_compound_assignment.txt375
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0049_async_block.txt49
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0050_async_block_as_argument.txt60
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.txt77
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0052_for_range_block.txt138
-rw-r--r--website/src/index.html21
-rw-r--r--website/src/wasm-demo/index.html13
-rw-r--r--website/website-gen/Cargo.toml9
-rw-r--r--website/website-gen/src/main.rs64
209 files changed, 11023 insertions, 10257 deletions
diff --git a/.cargo/config b/.cargo/config
index 92a3acfd0..9f9b24a49 100644
--- a/.cargo/config
+++ b/.cargo/config
@@ -5,6 +5,8 @@ gen-syntax = "run --package ra_tools --bin ra_tools -- gen-syntax"
5# Extracts the tests from 5# Extracts the tests from
6gen-tests = "run --package ra_tools --bin ra_tools -- gen-tests" 6gen-tests = "run --package ra_tools --bin ra_tools -- gen-tests"
7 7
8build-website = "run --package website-gen"
9
8# Installs the visual studio code extension 10# Installs the visual studio code extension
9install-ra = "run --package ra_tools --bin ra_tools -- install-ra" 11install-ra = "run --package ra_tools --bin ra_tools -- install-ra"
10install-code = "run --package ra_tools --bin ra_tools -- install-ra" # just an alias 12install-code = "run --package ra_tools --bin ra_tools -- install-ra" # just an alias
diff --git a/.travis.yml b/.travis.yml
index 52af05375..c198cc5f7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -28,7 +28,7 @@ matrix:
28 language: rust 28 language: rust
29 rust: stable 29 rust: stable
30 script: 30 script:
31 - cargo doc --all --no-deps 31 - cargo build-website
32 env: 32 env:
33 - RUSTFLAGS="-D warnings", CARGO_INCREMENTAL=0 33 - RUSTFLAGS="-D warnings", CARGO_INCREMENTAL=0
34 34
@@ -59,7 +59,7 @@ deploy:
59 skip-cleanup: true 59 skip-cleanup: true
60 github-token: $DOCS_TOKEN # Set in the settings page of your repository, as a secure variable 60 github-token: $DOCS_TOKEN # Set in the settings page of your repository, as a secure variable
61 keep-history: true 61 keep-history: true
62 local-dir: target/doc 62 local-dir: target/website/
63 on: 63 on:
64 branch: master 64 branch: master
65 condition: $DEPLOY_DOCS = 1 65 condition: $DEPLOY_DOCS = 1
diff --git a/Cargo.lock b/Cargo.lock
index 9c630f370..27e0a82af 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -122,7 +122,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
122[[package]] 122[[package]]
123name = "chalk-engine" 123name = "chalk-engine"
124version = "0.9.0" 124version = "0.9.0"
125source = "git+https://github.com/rust-lang/chalk.git#c9314e425e49969c33cabcb8fac7da6eac3c5073" 125source = "git+https://github.com/rust-lang/chalk.git#5c6cea8bc02c8bc282223aa12528648b5cd0b6e4"
126dependencies = [ 126dependencies = [
127 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)", 127 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)",
128 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 128 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -132,7 +132,7 @@ dependencies = [
132[[package]] 132[[package]]
133name = "chalk-ir" 133name = "chalk-ir"
134version = "0.1.0" 134version = "0.1.0"
135source = "git+https://github.com/rust-lang/chalk.git#c9314e425e49969c33cabcb8fac7da6eac3c5073" 135source = "git+https://github.com/rust-lang/chalk.git#5c6cea8bc02c8bc282223aa12528648b5cd0b6e4"
136dependencies = [ 136dependencies = [
137 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)", 137 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)",
138 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)", 138 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)",
@@ -142,7 +142,7 @@ dependencies = [
142[[package]] 142[[package]]
143name = "chalk-macros" 143name = "chalk-macros"
144version = "0.1.1" 144version = "0.1.1"
145source = "git+https://github.com/rust-lang/chalk.git#c9314e425e49969c33cabcb8fac7da6eac3c5073" 145source = "git+https://github.com/rust-lang/chalk.git#5c6cea8bc02c8bc282223aa12528648b5cd0b6e4"
146dependencies = [ 146dependencies = [
147 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 147 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
148] 148]
@@ -150,7 +150,7 @@ dependencies = [
150[[package]] 150[[package]]
151name = "chalk-rust-ir" 151name = "chalk-rust-ir"
152version = "0.1.0" 152version = "0.1.0"
153source = "git+https://github.com/rust-lang/chalk.git#c9314e425e49969c33cabcb8fac7da6eac3c5073" 153source = "git+https://github.com/rust-lang/chalk.git#5c6cea8bc02c8bc282223aa12528648b5cd0b6e4"
154dependencies = [ 154dependencies = [
155 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)", 155 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)",
156 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)", 156 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)",
@@ -160,7 +160,7 @@ dependencies = [
160[[package]] 160[[package]]
161name = "chalk-solve" 161name = "chalk-solve"
162version = "0.1.0" 162version = "0.1.0"
163source = "git+https://github.com/rust-lang/chalk.git#c9314e425e49969c33cabcb8fac7da6eac3c5073" 163source = "git+https://github.com/rust-lang/chalk.git#5c6cea8bc02c8bc282223aa12528648b5cd0b6e4"
164dependencies = [ 164dependencies = [
165 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)", 165 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)",
166 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)", 166 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)",
@@ -665,7 +665,7 @@ dependencies = [
665 665
666[[package]] 666[[package]]
667name = "lsp-types" 667name = "lsp-types"
668version = "0.60.0" 668version = "0.61.0"
669source = "registry+https://github.com/rust-lang/crates.io-index" 669source = "registry+https://github.com/rust-lang/crates.io-index"
670dependencies = [ 670dependencies = [
671 "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 671 "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -800,11 +800,8 @@ dependencies = [
800 800
801[[package]] 801[[package]]
802name = "once_cell" 802name = "once_cell"
803version = "0.2.7" 803version = "1.0.1"
804source = "registry+https://github.com/rust-lang/crates.io-index" 804source = "registry+https://github.com/rust-lang/crates.io-index"
805dependencies = [
806 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
807]
808 805
809[[package]] 806[[package]]
810name = "ordermap" 807name = "ordermap"
@@ -950,7 +947,7 @@ dependencies = [
950 "format-buf 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 947 "format-buf 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
951 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 948 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
952 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 949 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
953 "once_cell 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 950 "once_cell 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
954 "ra_db 0.1.0", 951 "ra_db 0.1.0",
955 "ra_fmt 0.1.0", 952 "ra_fmt 0.1.0",
956 "ra_hir 0.1.0", 953 "ra_hir 0.1.0",
@@ -1020,7 +1017,7 @@ dependencies = [
1020 "insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 1017 "insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
1021 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", 1018 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
1022 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1019 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
1023 "once_cell 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 1020 "once_cell 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1024 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 1021 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
1025 "ra_arena 0.1.0", 1022 "ra_arena 0.1.0",
1026 "ra_db 0.1.0", 1023 "ra_db 0.1.0",
@@ -1069,7 +1066,7 @@ dependencies = [
1069 "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1066 "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1070 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1067 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
1071 "lsp-server 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1068 "lsp-server 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1072 "lsp-types 0.60.0 (registry+https://github.com/rust-lang/crates.io-index)", 1069 "lsp-types 0.61.0 (registry+https://github.com/rust-lang/crates.io-index)",
1073 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 1070 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
1074 "ra_ide_api 0.1.0", 1071 "ra_ide_api 0.1.0",
1075 "ra_prof 0.1.0", 1072 "ra_prof 0.1.0",
@@ -1115,7 +1112,7 @@ dependencies = [
1115 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 1112 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
1116 "jemalloc-ctl 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 1113 "jemalloc-ctl 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
1117 "jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 1114 "jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
1118 "once_cell 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 1115 "once_cell 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1119] 1116]
1120 1117
1121[[package]] 1118[[package]]
@@ -1780,6 +1777,13 @@ version = "0.5.0"
1780source = "registry+https://github.com/rust-lang/crates.io-index" 1777source = "registry+https://github.com/rust-lang/crates.io-index"
1781 1778
1782[[package]] 1779[[package]]
1780name = "website-gen"
1781version = "0.0.0"
1782dependencies = [
1783 "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
1784]
1785
1786[[package]]
1783name = "winapi" 1787name = "winapi"
1784version = "0.2.8" 1788version = "0.2.8"
1785source = "registry+https://github.com/rust-lang/crates.io-index" 1789source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1920,7 +1924,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1920"checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc" 1924"checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc"
1921"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 1925"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
1922"checksum lsp-server 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "148cfb1c0b3295c23d9fb4a20fd1b242f5e6f46c525fdcc7f5c0a65710362012" 1926"checksum lsp-server 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "148cfb1c0b3295c23d9fb4a20fd1b242f5e6f46c525fdcc7f5c0a65710362012"
1923"checksum lsp-types 0.60.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe3edefcd66dde1f7f1df706f46520a3c93adc5ca4bc5747da6621195e894efd" 1927"checksum lsp-types 0.61.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa3268fbe8beb2795c2fb327bf44f4f3d24f5fe9ebc18d7e2980afd444d72bcf"
1924"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 1928"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
1925"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" 1929"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
1926"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" 1930"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f"
@@ -1934,7 +1938,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1934"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" 1938"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
1935"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" 1939"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273"
1936"checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee" 1940"checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee"
1937"checksum once_cell 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d1a13503127ae8c93c0e2c817d74895b0af4df9132ec9be3ea42dd1656cd6e9" 1941"checksum once_cell 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c9192c5a4c3b5488dae8d3886ef9df6b5eb246d36323dc7a5078595a154e7771"
1938"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" 1942"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
1939"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" 1943"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
1940"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" 1944"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
diff --git a/Cargo.toml b/Cargo.toml
index e44c9570f..317c63795 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,5 @@
1[workspace] 1[workspace]
2members = [ "crates/*" ] 2members = [ "crates/*", "website/website-gen" ]
3 3
4[profile.release] 4[profile.release]
5incremental = true 5incremental = true
diff --git a/README.md b/README.md
index e8f0e953e..50918ee5e 100644
--- a/README.md
+++ b/README.md
@@ -55,7 +55,7 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frls-2.2E0
55## Quick Links 55## Quick Links
56 56
57* Work List: https://paper.dropbox.com/doc/RLS-2.0-work-list--AZ3BgHKKCtqszbsi3gi6sjchAQ-42vbnxzuKq2lKwW0mkn8Y 57* Work List: https://paper.dropbox.com/doc/RLS-2.0-work-list--AZ3BgHKKCtqszbsi3gi6sjchAQ-42vbnxzuKq2lKwW0mkn8Y
58* API docs: https://rust-analyzer.github.io/rust-analyzer/ra_ide_api/index.html 58* API docs: https://rust-analyzer.github.io/rust-analyzer/api-docs/ra_ide_api/
59* CI: https://travis-ci.org/rust-analyzer/rust-analyzer 59* CI: https://travis-ci.org/rust-analyzer/rust-analyzer
60 60
61## License 61## License
diff --git a/crates/ra_assists/Cargo.toml b/crates/ra_assists/Cargo.toml
index 2113286a3..635d87611 100644
--- a/crates/ra_assists/Cargo.toml
+++ b/crates/ra_assists/Cargo.toml
@@ -6,7 +6,7 @@ authors = ["rust-analyzer developers"]
6 6
7[dependencies] 7[dependencies]
8format-buf = "1.0.0" 8format-buf = "1.0.0"
9once_cell = "0.2.0" 9once_cell = "1.0.1"
10join_to_string = "0.1.3" 10join_to_string = "0.1.3"
11itertools = "0.8.0" 11itertools = "0.8.0"
12arrayvec = "0.4.10" 12arrayvec = "0.4.10"
diff --git a/crates/ra_assists/src/ast_editor.rs b/crates/ra_assists/src/ast_editor.rs
index 6815638dc..048478662 100644
--- a/crates/ra_assists/src/ast_editor.rs
+++ b/crates/ra_assists/src/ast_editor.rs
@@ -274,7 +274,7 @@ impl AstBuilder<ast::Block> {
274 274
275impl AstBuilder<ast::Expr> { 275impl AstBuilder<ast::Expr> {
276 fn from_text(text: &str) -> ast::Expr { 276 fn from_text(text: &str) -> ast::Expr {
277 ast_node_from_file_text(&format!("fn f() {{ {}; }}", text)) 277 ast_node_from_file_text(&format!("const C: () = {};", text))
278 } 278 }
279 279
280 pub fn unit() -> ast::Expr { 280 pub fn unit() -> ast::Expr {
diff --git a/crates/ra_assists/src/introduce_variable.rs b/crates/ra_assists/src/introduce_variable.rs
index 95c18d0e3..470ffe120 100644
--- a/crates/ra_assists/src/introduce_variable.rs
+++ b/crates/ra_assists/src/introduce_variable.rs
@@ -3,7 +3,8 @@ use hir::db::HirDatabase;
3use ra_syntax::{ 3use ra_syntax::{
4 ast::{self, AstNode}, 4 ast::{self, AstNode},
5 SyntaxKind::{ 5 SyntaxKind::{
6 BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, WHITESPACE, 6 BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR,
7 WHITESPACE,
7 }, 8 },
8 SyntaxNode, TextUnit, 9 SyntaxNode, TextUnit,
9}; 10};
@@ -80,10 +81,12 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option
80/// In general that's true for any expression, but in some cases that would produce invalid code. 81/// In general that's true for any expression, but in some cases that would produce invalid code.
81fn valid_target_expr(node: SyntaxNode) -> Option<ast::Expr> { 82fn valid_target_expr(node: SyntaxNode) -> Option<ast::Expr> {
82 match node.kind() { 83 match node.kind() {
83 PATH_EXPR => None, 84 PATH_EXPR | LOOP_EXPR => None,
84 BREAK_EXPR => ast::BreakExpr::cast(node).and_then(|e| e.expr()), 85 BREAK_EXPR => ast::BreakExpr::cast(node).and_then(|e| e.expr()),
85 RETURN_EXPR => ast::ReturnExpr::cast(node).and_then(|e| e.expr()), 86 RETURN_EXPR => ast::ReturnExpr::cast(node).and_then(|e| e.expr()),
86 LOOP_EXPR => ast::ReturnExpr::cast(node).and_then(|e| e.expr()), 87 BLOCK_EXPR => {
88 ast::BlockExpr::cast(node).filter(|it| it.is_standalone()).map(ast::Expr::from)
89 }
87 _ => ast::Expr::cast(node), 90 _ => ast::Expr::cast(node),
88 } 91 }
89} 92}
diff --git a/crates/ra_assists/src/move_guard.rs b/crates/ra_assists/src/move_guard.rs
index 127c9e068..699221e33 100644
--- a/crates/ra_assists/src/move_guard.rs
+++ b/crates/ra_assists/src/move_guard.rs
@@ -65,9 +65,9 @@ pub(crate) fn move_arm_cond_to_match_guard(mut ctx: AssistCtx<impl HirDatabase>)
65 "move condition to match guard", 65 "move condition to match guard",
66 |edit| { 66 |edit| {
67 edit.target(if_expr.syntax().text_range()); 67 edit.target(if_expr.syntax().text_range());
68 let then_only_expr = then_block.statements().next().is_none(); 68 let then_only_expr = then_block.block().and_then(|it| it.statements().next()).is_none();
69 69
70 match &then_block.expr() { 70 match &then_block.block().and_then(|it| it.expr()) {
71 Some(then_expr) if then_only_expr => { 71 Some(then_expr) if then_only_expr => {
72 edit.replace(if_expr.syntax().text_range(), then_expr.syntax().text()) 72 edit.replace(if_expr.syntax().text_range(), then_expr.syntax().text())
73 } 73 }
diff --git a/crates/ra_assists/src/replace_if_let_with_match.rs b/crates/ra_assists/src/replace_if_let_with_match.rs
index c0bf6d235..401835c57 100644
--- a/crates/ra_assists/src/replace_if_let_with_match.rs
+++ b/crates/ra_assists/src/replace_if_let_with_match.rs
@@ -1,3 +1,4 @@
1use format_buf::format;
1use hir::db::HirDatabase; 2use hir::db::HirDatabase;
2use ra_fmt::extract_trivial_expression; 3use ra_fmt::extract_trivial_expression;
3use ra_syntax::{ast, AstNode}; 4use ra_syntax::{ast, AstNode};
@@ -25,16 +26,21 @@ pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx<impl HirDatabase>) ->
25 ctx.build() 26 ctx.build()
26} 27}
27 28
28fn build_match_expr(expr: ast::Expr, pat1: ast::Pat, arm1: ast::Block, arm2: ast::Block) -> String { 29fn build_match_expr(
30 expr: ast::Expr,
31 pat1: ast::Pat,
32 arm1: ast::BlockExpr,
33 arm2: ast::BlockExpr,
34) -> String {
29 let mut buf = String::new(); 35 let mut buf = String::new();
30 buf.push_str(&format!("match {} {{\n", expr.syntax().text())); 36 format!(buf, "match {} {{\n", expr.syntax().text());
31 buf.push_str(&format!(" {} => {}\n", pat1.syntax().text(), format_arm(&arm1))); 37 format!(buf, " {} => {}\n", pat1.syntax().text(), format_arm(&arm1));
32 buf.push_str(&format!(" _ => {}\n", format_arm(&arm2))); 38 format!(buf, " _ => {}\n", format_arm(&arm2));
33 buf.push_str("}"); 39 buf.push_str("}");
34 buf 40 buf
35} 41}
36 42
37fn format_arm(block: &ast::Block) -> String { 43fn format_arm(block: &ast::BlockExpr) -> String {
38 match extract_trivial_expression(block) { 44 match extract_trivial_expression(block) {
39 None => block.syntax().text().to_string(), 45 None => block.syntax().text().to_string(),
40 Some(e) => format!("{},", e.syntax().text()), 46 Some(e) => format!("{},", e.syntax().text()),
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs
index 7e7e6c073..1fad5b233 100644
--- a/crates/ra_cli/src/analysis_stats.rs
+++ b/crates/ra_cli/src/analysis_stats.rs
@@ -1,7 +1,7 @@
1use std::{collections::HashSet, fmt::Write, path::Path, time::Instant}; 1use std::{collections::HashSet, fmt::Write, path::Path, time::Instant};
2 2
3use ra_db::SourceDatabase; 3use ra_db::SourceDatabase;
4use ra_hir::{Crate, HasSource, ImplItem, ModuleDef, Ty}; 4use ra_hir::{Crate, HasBodySource, HasSource, HirDisplay, ImplItem, ModuleDef, Ty, TypeWalk};
5use ra_syntax::AstNode; 5use ra_syntax::AstNode;
6 6
7use crate::Result; 7use crate::Result;
@@ -66,6 +66,7 @@ pub fn run(verbose: bool, memory_usage: bool, path: &Path, only: Option<&str>) -
66 let mut num_exprs = 0; 66 let mut num_exprs = 0;
67 let mut num_exprs_unknown = 0; 67 let mut num_exprs_unknown = 0;
68 let mut num_exprs_partially_unknown = 0; 68 let mut num_exprs_partially_unknown = 0;
69 let mut num_type_mismatches = 0;
69 for f in funcs { 70 for f in funcs {
70 let name = f.name(db); 71 let name = f.name(db);
71 let mut msg = format!("processing: {}", name); 72 let mut msg = format!("processing: {}", name);
@@ -100,6 +101,42 @@ pub fn run(verbose: bool, memory_usage: bool, path: &Path, only: Option<&str>) -
100 num_exprs_partially_unknown += 1; 101 num_exprs_partially_unknown += 1;
101 } 102 }
102 } 103 }
104 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) {
105 num_type_mismatches += 1;
106 if verbose {
107 let src = f.expr_source(db, expr_id);
108 if let Some(src) = src {
109 // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly
110 let original_file = src.file_id.original_file(db);
111 let path = db.file_relative_path(original_file);
112 let line_index = host.analysis().file_line_index(original_file).unwrap();
113 let text_range = src
114 .ast
115 .either(|it| it.syntax().text_range(), |it| it.syntax().text_range());
116 let (start, end) = (
117 line_index.line_col(text_range.start()),
118 line_index.line_col(text_range.end()),
119 );
120 bar.println(format!(
121 "{} {}:{}-{}:{}: Expected {}, got {}",
122 path.display(),
123 start.line + 1,
124 start.col_utf16,
125 end.line + 1,
126 end.col_utf16,
127 mismatch.expected.display(db),
128 mismatch.actual.display(db)
129 ));
130 } else {
131 bar.println(format!(
132 "{}: Expected {}, got {}",
133 name,
134 mismatch.expected.display(db),
135 mismatch.actual.display(db)
136 ));
137 }
138 }
139 }
103 } 140 }
104 bar.inc(1); 141 bar.inc(1);
105 } 142 }
@@ -115,6 +152,7 @@ pub fn run(verbose: bool, memory_usage: bool, path: &Path, only: Option<&str>) -
115 num_exprs_partially_unknown, 152 num_exprs_partially_unknown,
116 (num_exprs_partially_unknown * 100 / num_exprs) 153 (num_exprs_partially_unknown * 100 / num_exprs)
117 ); 154 );
155 println!("Type mismatches: {}", num_type_mismatches);
118 println!("Inference: {:?}, {}", inference_time.elapsed(), ra_prof::memory_usage()); 156 println!("Inference: {:?}, {}", inference_time.elapsed(), ra_prof::memory_usage());
119 println!("Total: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage()); 157 println!("Total: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage());
120 158
diff --git a/crates/ra_fmt/src/lib.rs b/crates/ra_fmt/src/lib.rs
index b09478d7a..e22ac9753 100644
--- a/crates/ra_fmt/src/lib.rs
+++ b/crates/ra_fmt/src/lib.rs
@@ -34,7 +34,8 @@ fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> {
34 successors(token.prev_token(), |token| token.prev_token()) 34 successors(token.prev_token(), |token| token.prev_token())
35} 35}
36 36
37pub fn extract_trivial_expression(block: &ast::Block) -> Option<ast::Expr> { 37pub fn extract_trivial_expression(expr: &ast::BlockExpr) -> Option<ast::Expr> {
38 let block = expr.block()?;
38 let expr = block.expr()?; 39 let expr = block.expr()?;
39 if expr.syntax().text().contains_char('\n') { 40 if expr.syntax().text().contains_char('\n') {
40 return None; 41 return None;
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml
index 646c96692..d9bed4dda 100644
--- a/crates/ra_hir/Cargo.toml
+++ b/crates/ra_hir/Cargo.toml
@@ -11,7 +11,7 @@ relative-path = "0.4.0"
11rustc-hash = "1.0" 11rustc-hash = "1.0"
12parking_lot = "0.9.0" 12parking_lot = "0.9.0"
13ena = "0.13" 13ena = "0.13"
14once_cell = "0.2" 14once_cell = "1.0.1"
15 15
16ra_syntax = { path = "../ra_syntax" } 16ra_syntax = { path = "../ra_syntax" }
17ra_arena = { path = "../ra_arena" } 17ra_arena = { path = "../ra_arena" }
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 66a58efed..f7efc1b66 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -510,18 +510,6 @@ pub enum DefWithBody {
510impl_froms!(DefWithBody: Function, Const, Static); 510impl_froms!(DefWithBody: Function, Const, Static);
511 511
512impl DefWithBody { 512impl DefWithBody {
513 pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
514 db.infer(self)
515 }
516
517 pub fn body(self, db: &impl HirDatabase) -> Arc<Body> {
518 db.body_hir(self)
519 }
520
521 pub fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
522 db.body_with_source_map(self).1
523 }
524
525 /// Builds a resolver for code inside this item. 513 /// Builds a resolver for code inside this item.
526 pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver { 514 pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver {
527 match self { 515 match self {
@@ -532,6 +520,43 @@ impl DefWithBody {
532 } 520 }
533} 521}
534 522
523pub trait HasBody: Copy {
524 fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult>;
525 fn body(self, db: &impl HirDatabase) -> Arc<Body>;
526 fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap>;
527}
528
529impl<T> HasBody for T
530where
531 T: Into<DefWithBody> + Copy + HasSource,
532{
533 fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
534 db.infer(self.into())
535 }
536
537 fn body(self, db: &impl HirDatabase) -> Arc<Body> {
538 db.body_hir(self.into())
539 }
540
541 fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
542 db.body_with_source_map(self.into()).1
543 }
544}
545
546impl HasBody for DefWithBody {
547 fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
548 db.infer(self)
549 }
550
551 fn body(self, db: &impl HirDatabase) -> Arc<Body> {
552 db.body_hir(self)
553 }
554
555 fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
556 db.body_with_source_map(self).1
557 }
558}
559
535#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 560#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
536pub struct Function { 561pub struct Function {
537 pub(crate) id: FunctionId, 562 pub(crate) id: FunctionId,
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs
index 32bd9c661..b9ffb0c7a 100644
--- a/crates/ra_hir/src/code_model/src.rs
+++ b/crates/ra_hir/src/code_model/src.rs
@@ -1,11 +1,15 @@
1use ra_syntax::ast; 1use ra_syntax::{
2 ast::{self, AstNode},
3 SyntaxNode,
4};
2 5
3use crate::{ 6use crate::{
4 ids::AstItemDef, AstDatabase, Const, DefDatabase, Enum, EnumVariant, FieldSource, Function, 7 ids::AstItemDef, AstDatabase, Const, DefDatabase, Either, Enum, EnumVariant, FieldSource,
5 HirFileId, MacroDef, Module, ModuleSource, Static, Struct, StructField, Trait, TypeAlias, 8 Function, HasBody, HirDatabase, HirFileId, MacroDef, Module, ModuleSource, Static, Struct,
6 Union, 9 StructField, Trait, TypeAlias, Union,
7}; 10};
8 11
12#[derive(Debug, PartialEq, Eq, Clone, Copy)]
9pub struct Source<T> { 13pub struct Source<T> {
10 pub file_id: HirFileId, 14 pub file_id: HirFileId,
11 pub ast: T, 15 pub ast: T,
@@ -16,6 +20,15 @@ pub trait HasSource {
16 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<Self::Ast>; 20 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<Self::Ast>;
17} 21}
18 22
23impl<T> Source<T> {
24 pub(crate) fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
25 Source { file_id: self.file_id, ast: f(self.ast) }
26 }
27 pub(crate) fn file_syntax(&self, db: &impl AstDatabase) -> SyntaxNode {
28 db.parse_or_expand(self.file_id).expect("source created from invalid file")
29 }
30}
31
19/// NB: Module is !HasSource, because it has two source nodes at the same time: 32/// NB: Module is !HasSource, because it has two source nodes at the same time:
20/// definition and declaration. 33/// definition and declaration.
21impl Module { 34impl Module {
@@ -108,3 +121,27 @@ impl HasSource for MacroDef {
108 Source { file_id: self.id.0.file_id(), ast: self.id.0.to_node(db) } 121 Source { file_id: self.id.0.file_id(), ast: self.id.0.to_node(db) }
109 } 122 }
110} 123}
124
125pub trait HasBodySource: HasBody + HasSource
126where
127 Self::Ast: AstNode,
128{
129 fn expr_source(
130 self,
131 db: &impl HirDatabase,
132 expr_id: crate::expr::ExprId,
133 ) -> Option<Source<Either<ast::Expr, ast::RecordField>>> {
134 let source_map = self.body_source_map(db);
135 let source_ptr = source_map.expr_syntax(expr_id)?;
136 let root = source_ptr.file_syntax(db);
137 let source = source_ptr.map(|ast| ast.map(|it| it.to_node(&root), |it| it.to_node(&root)));
138 Some(source)
139 }
140}
141
142impl<T> HasBodySource for T
143where
144 T: HasBody + HasSource,
145 T::Ast: AstNode,
146{
147}
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 7cdc7555c..fc21e269f 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -1,36 +1,30 @@
1use std::ops::Index; 1pub(crate) mod lower;
2use std::sync::Arc; 2pub(crate) mod scope;
3pub(crate) mod validation;
3 4
4use rustc_hash::FxHashMap; 5use std::{ops::Index, sync::Arc};
5 6
6use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; 7use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
7use ra_syntax::{ 8use ra_syntax::{ast, AstPtr};
8 ast::{ 9use rustc_hash::FxHashMap;
9 self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, NameOwner,
10 TryBlockBodyOwner, TypeAscriptionOwner,
11 },
12 AstNode, AstPtr, SyntaxNodePtr,
13};
14use test_utils::tested_by;
15 10
16use crate::{ 11use crate::{
17 name::{AsName, SELF_PARAM},
18 path::GenericArgs, 12 path::GenericArgs,
19 ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, 13 ty::primitive::{UncertainFloatTy, UncertainIntTy},
20 type_ref::{Mutability, TypeRef}, 14 type_ref::{Mutability, TypeRef},
21 DefWithBody, Either, HasSource, HirDatabase, HirFileId, MacroCallLoc, MacroFileKind, Name, 15 DefWithBody, Either, HasSource, HirDatabase, Name, Path, Resolver, Source,
22 Path, Resolver,
23}; 16};
24 17
25pub use self::scope::ExprScopes; 18pub use self::scope::ExprScopes;
26 19
27pub(crate) mod scope;
28pub(crate) mod validation;
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 20#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
31pub struct ExprId(RawId); 21pub struct ExprId(RawId);
32impl_arena_id!(ExprId); 22impl_arena_id!(ExprId);
33 23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
25pub struct PatId(RawId);
26impl_arena_id!(PatId);
27
34/// The body of an item (function, const etc.). 28/// The body of an item (function, const etc.).
35#[derive(Debug, Eq, PartialEq)] 29#[derive(Debug, Eq, PartialEq)]
36pub struct Body { 30pub struct Body {
@@ -49,22 +43,32 @@ pub struct Body {
49 body_expr: ExprId, 43 body_expr: ExprId,
50} 44}
51 45
46type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>;
47type ExprSource = Source<ExprPtr>;
48
49type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
50type PatSource = Source<PatPtr>;
51
52/// An item body together with the mapping from syntax nodes to HIR expression 52/// An item body together with the mapping from syntax nodes to HIR expression
53/// IDs. This is needed to go from e.g. a position in a file to the HIR 53/// IDs. This is needed to go from e.g. a position in a file to the HIR
54/// expression containing it; but for type inference etc., we want to operate on 54/// expression containing it; but for type inference etc., we want to operate on
55/// a structure that is agnostic to the actual positions of expressions in the 55/// a structure that is agnostic to the actual positions of expressions in the
56/// file, so that we don't recompute types whenever some whitespace is typed. 56/// file, so that we don't recompute types whenever some whitespace is typed.
57///
58/// One complication here is that, due to macro expansion, a single `Body` might
59/// be spread across several files. So, for each ExprId and PatId, we record
60/// both the HirFileId and the position inside the file. However, we only store
61/// AST -> ExprId mapping for non-macro files, as it is not clear how to handle
62/// this properly for macros.
57#[derive(Default, Debug, Eq, PartialEq)] 63#[derive(Default, Debug, Eq, PartialEq)]
58pub struct BodySourceMap { 64pub struct BodySourceMap {
59 expr_map: FxHashMap<SyntaxNodePtr, ExprId>, 65 expr_map: FxHashMap<ExprPtr, ExprId>,
60 expr_map_back: ArenaMap<ExprId, SyntaxNodePtr>, 66 expr_map_back: ArenaMap<ExprId, ExprSource>,
61 pat_map: FxHashMap<PatPtr, PatId>, 67 pat_map: FxHashMap<PatPtr, PatId>,
62 pat_map_back: ArenaMap<PatId, PatPtr>, 68 pat_map_back: ArenaMap<PatId, PatSource>,
63 field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>, 69 field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>,
64} 70}
65 71
66type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
67
68impl Body { 72impl Body {
69 pub fn params(&self) -> &[PatId] { 73 pub fn params(&self) -> &[PatId] {
70 &self.params 74 &self.params
@@ -128,20 +132,16 @@ impl Index<PatId> for Body {
128} 132}
129 133
130impl BodySourceMap { 134impl BodySourceMap {
131 pub(crate) fn expr_syntax(&self, expr: ExprId) -> Option<SyntaxNodePtr> { 135 pub(crate) fn expr_syntax(&self, expr: ExprId) -> Option<ExprSource> {
132 self.expr_map_back.get(expr).cloned() 136 self.expr_map_back.get(expr).copied()
133 }
134
135 pub(crate) fn syntax_expr(&self, ptr: SyntaxNodePtr) -> Option<ExprId> {
136 self.expr_map.get(&ptr).cloned()
137 } 137 }
138 138
139 pub(crate) fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> { 139 pub(crate) fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> {
140 self.expr_map.get(&SyntaxNodePtr::new(node.syntax())).cloned() 140 self.expr_map.get(&Either::A(AstPtr::new(node))).cloned()
141 } 141 }
142 142
143 pub(crate) fn pat_syntax(&self, pat: PatId) -> Option<PatPtr> { 143 pub(crate) fn pat_syntax(&self, pat: PatId) -> Option<PatSource> {
144 self.pat_map_back.get(pat).cloned() 144 self.pat_map_back.get(pat).copied()
145 } 145 }
146 146
147 pub(crate) fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { 147 pub(crate) fn node_pat(&self, node: &ast::Pat) -> Option<PatId> {
@@ -436,10 +436,6 @@ impl Expr {
436 } 436 }
437} 437}
438 438
439#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
440pub struct PatId(RawId);
441impl_arena_id!(PatId);
442
443/// Explicit binding annotations given in the HIR for a binding. Note 439/// Explicit binding annotations given in the HIR for a binding. Note
444/// that this is not the final binding *mode* that we infer after type 440/// that this is not the final binding *mode* that we infer after type
445/// inference. 441/// inference.
@@ -485,7 +481,7 @@ pub enum Pat {
485 Missing, 481 Missing,
486 Wild, 482 Wild,
487 Tuple(Vec<PatId>), 483 Tuple(Vec<PatId>),
488 Struct { 484 Record {
489 path: Option<Path>, 485 path: Option<Path>,
490 args: Vec<RecordFieldPat>, 486 args: Vec<RecordFieldPat>,
491 // FIXME: 'ellipsis' option 487 // FIXME: 'ellipsis' option
@@ -531,7 +527,7 @@ impl Pat {
531 let total_iter = prefix.iter().chain(rest.iter()).chain(suffix.iter()); 527 let total_iter = prefix.iter().chain(rest.iter()).chain(suffix.iter());
532 total_iter.copied().for_each(f); 528 total_iter.copied().for_each(f);
533 } 529 }
534 Pat::Struct { args, .. } => { 530 Pat::Record { args, .. } => {
535 args.iter().map(|f| f.pat).for_each(f); 531 args.iter().map(|f| f.pat).for_each(f);
536 } 532 }
537 } 533 }
@@ -539,624 +535,29 @@ impl Pat {
539} 535}
540 536
541// Queries 537// Queries
542
543pub(crate) struct ExprCollector<DB> {
544 db: DB,
545 owner: DefWithBody,
546 exprs: Arena<ExprId, Expr>,
547 pats: Arena<PatId, Pat>,
548 source_map: BodySourceMap,
549 params: Vec<PatId>,
550 body_expr: Option<ExprId>,
551 resolver: Resolver,
552 // Expr collector expands macros along the way. original points to the file
553 // we started with, current points to the current macro expansion. source
554 // maps don't support macros yet, so we only record info into source map if
555 // current == original (see #1196)
556 original_file_id: HirFileId,
557 current_file_id: HirFileId,
558}
559
560impl<'a, DB> ExprCollector<&'a DB>
561where
562 DB: HirDatabase,
563{
564 fn new(owner: DefWithBody, file_id: HirFileId, resolver: Resolver, db: &'a DB) -> Self {
565 ExprCollector {
566 owner,
567 resolver,
568 db,
569 exprs: Arena::default(),
570 pats: Arena::default(),
571 source_map: BodySourceMap::default(),
572 params: Vec::new(),
573 body_expr: None,
574 original_file_id: file_id,
575 current_file_id: file_id,
576 }
577 }
578 fn alloc_expr(&mut self, expr: Expr, syntax_ptr: SyntaxNodePtr) -> ExprId {
579 let id = self.exprs.alloc(expr);
580 if self.current_file_id == self.original_file_id {
581 self.source_map.expr_map.insert(syntax_ptr, id);
582 self.source_map.expr_map_back.insert(id, syntax_ptr);
583 }
584 id
585 }
586
587 fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
588 let id = self.pats.alloc(pat);
589
590 if self.current_file_id == self.original_file_id {
591 self.source_map.pat_map.insert(ptr, id);
592 self.source_map.pat_map_back.insert(id, ptr);
593 }
594
595 id
596 }
597
598 fn empty_block(&mut self) -> ExprId {
599 let block = Expr::Block { statements: Vec::new(), tail: None };
600 self.exprs.alloc(block)
601 }
602
603 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
604 let syntax_ptr = SyntaxNodePtr::new(expr.syntax());
605 match expr {
606 ast::Expr::IfExpr(e) => {
607 let then_branch = self.collect_block_opt(e.then_branch());
608
609 let else_branch = e.else_branch().map(|b| match b {
610 ast::ElseBranch::Block(it) => self.collect_block(it),
611 ast::ElseBranch::IfExpr(elif) => {
612 let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap();
613 self.collect_expr(expr)
614 }
615 });
616
617 let condition = match e.condition() {
618 None => self.exprs.alloc(Expr::Missing),
619 Some(condition) => match condition.pat() {
620 None => self.collect_expr_opt(condition.expr()),
621 // if let -- desugar to match
622 Some(pat) => {
623 let pat = self.collect_pat(pat);
624 let match_expr = self.collect_expr_opt(condition.expr());
625 let placeholder_pat = self.pats.alloc(Pat::Missing);
626 let arms = vec![
627 MatchArm { pats: vec![pat], expr: then_branch, guard: None },
628 MatchArm {
629 pats: vec![placeholder_pat],
630 expr: else_branch.unwrap_or_else(|| self.empty_block()),
631 guard: None,
632 },
633 ];
634 return self
635 .alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr);
636 }
637 },
638 };
639
640 self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
641 }
642 ast::Expr::TryBlockExpr(e) => {
643 let body = self.collect_block_opt(e.try_body());
644 self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
645 }
646 ast::Expr::BlockExpr(e) => self.collect_block_opt(e.block()),
647 ast::Expr::LoopExpr(e) => {
648 let body = self.collect_block_opt(e.loop_body());
649 self.alloc_expr(Expr::Loop { body }, syntax_ptr)
650 }
651 ast::Expr::WhileExpr(e) => {
652 let body = self.collect_block_opt(e.loop_body());
653
654 let condition = match e.condition() {
655 None => self.exprs.alloc(Expr::Missing),
656 Some(condition) => match condition.pat() {
657 None => self.collect_expr_opt(condition.expr()),
658 // if let -- desugar to match
659 Some(pat) => {
660 tested_by!(infer_while_let);
661 let pat = self.collect_pat(pat);
662 let match_expr = self.collect_expr_opt(condition.expr());
663 let placeholder_pat = self.pats.alloc(Pat::Missing);
664 let break_ = self.exprs.alloc(Expr::Break { expr: None });
665 let arms = vec![
666 MatchArm { pats: vec![pat], expr: body, guard: None },
667 MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None },
668 ];
669 let match_expr =
670 self.exprs.alloc(Expr::Match { expr: match_expr, arms });
671 return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr);
672 }
673 },
674 };
675
676 self.alloc_expr(Expr::While { condition, body }, syntax_ptr)
677 }
678 ast::Expr::ForExpr(e) => {
679 let iterable = self.collect_expr_opt(e.iterable());
680 let pat = self.collect_pat_opt(e.pat());
681 let body = self.collect_block_opt(e.loop_body());
682 self.alloc_expr(Expr::For { iterable, pat, body }, syntax_ptr)
683 }
684 ast::Expr::CallExpr(e) => {
685 let callee = self.collect_expr_opt(e.expr());
686 let args = if let Some(arg_list) = e.arg_list() {
687 arg_list.args().map(|e| self.collect_expr(e)).collect()
688 } else {
689 Vec::new()
690 };
691 self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
692 }
693 ast::Expr::MethodCallExpr(e) => {
694 let receiver = self.collect_expr_opt(e.expr());
695 let args = if let Some(arg_list) = e.arg_list() {
696 arg_list.args().map(|e| self.collect_expr(e)).collect()
697 } else {
698 Vec::new()
699 };
700 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
701 let generic_args = e.type_arg_list().and_then(GenericArgs::from_ast);
702 self.alloc_expr(
703 Expr::MethodCall { receiver, method_name, args, generic_args },
704 syntax_ptr,
705 )
706 }
707 ast::Expr::MatchExpr(e) => {
708 let expr = self.collect_expr_opt(e.expr());
709 let arms = if let Some(match_arm_list) = e.match_arm_list() {
710 match_arm_list
711 .arms()
712 .map(|arm| MatchArm {
713 pats: arm.pats().map(|p| self.collect_pat(p)).collect(),
714 expr: self.collect_expr_opt(arm.expr()),
715 guard: arm
716 .guard()
717 .and_then(|guard| guard.expr())
718 .map(|e| self.collect_expr(e)),
719 })
720 .collect()
721 } else {
722 Vec::new()
723 };
724 self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
725 }
726 ast::Expr::PathExpr(e) => {
727 let path =
728 e.path().and_then(Path::from_ast).map(Expr::Path).unwrap_or(Expr::Missing);
729 self.alloc_expr(path, syntax_ptr)
730 }
731 ast::Expr::ContinueExpr(_e) => {
732 // FIXME: labels
733 self.alloc_expr(Expr::Continue, syntax_ptr)
734 }
735 ast::Expr::BreakExpr(e) => {
736 let expr = e.expr().map(|e| self.collect_expr(e));
737 self.alloc_expr(Expr::Break { expr }, syntax_ptr)
738 }
739 ast::Expr::ParenExpr(e) => {
740 let inner = self.collect_expr_opt(e.expr());
741 // make the paren expr point to the inner expression as well
742 self.source_map.expr_map.insert(syntax_ptr, inner);
743 inner
744 }
745 ast::Expr::ReturnExpr(e) => {
746 let expr = e.expr().map(|e| self.collect_expr(e));
747 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
748 }
749 ast::Expr::RecordLit(e) => {
750 let path = e.path().and_then(Path::from_ast);
751 let mut field_ptrs = Vec::new();
752 let record_lit = if let Some(nfl) = e.record_field_list() {
753 let fields = nfl
754 .fields()
755 .inspect(|field| field_ptrs.push(AstPtr::new(field)))
756 .map(|field| RecordLitField {
757 name: field
758 .name_ref()
759 .map(|nr| nr.as_name())
760 .unwrap_or_else(Name::missing),
761 expr: if let Some(e) = field.expr() {
762 self.collect_expr(e)
763 } else if let Some(nr) = field.name_ref() {
764 // field shorthand
765 let id = self.exprs.alloc(Expr::Path(Path::from_name_ref(&nr)));
766 self.source_map
767 .expr_map
768 .insert(SyntaxNodePtr::new(nr.syntax()), id);
769 self.source_map
770 .expr_map_back
771 .insert(id, SyntaxNodePtr::new(nr.syntax()));
772 id
773 } else {
774 self.exprs.alloc(Expr::Missing)
775 },
776 })
777 .collect();
778 let spread = nfl.spread().map(|s| self.collect_expr(s));
779 Expr::RecordLit { path, fields, spread }
780 } else {
781 Expr::RecordLit { path, fields: Vec::new(), spread: None }
782 };
783
784 let res = self.alloc_expr(record_lit, syntax_ptr);
785 for (i, ptr) in field_ptrs.into_iter().enumerate() {
786 self.source_map.field_map.insert((res, i), ptr);
787 }
788 res
789 }
790 ast::Expr::FieldExpr(e) => {
791 let expr = self.collect_expr_opt(e.expr());
792 let name = match e.field_access() {
793 Some(kind) => kind.as_name(),
794 _ => Name::missing(),
795 };
796 self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
797 }
798 ast::Expr::AwaitExpr(e) => {
799 let expr = self.collect_expr_opt(e.expr());
800 self.alloc_expr(Expr::Await { expr }, syntax_ptr)
801 }
802 ast::Expr::TryExpr(e) => {
803 let expr = self.collect_expr_opt(e.expr());
804 self.alloc_expr(Expr::Try { expr }, syntax_ptr)
805 }
806 ast::Expr::CastExpr(e) => {
807 let expr = self.collect_expr_opt(e.expr());
808 let type_ref = TypeRef::from_ast_opt(e.type_ref());
809 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
810 }
811 ast::Expr::RefExpr(e) => {
812 let expr = self.collect_expr_opt(e.expr());
813 let mutability = Mutability::from_mutable(e.is_mut());
814 self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr)
815 }
816 ast::Expr::PrefixExpr(e) => {
817 let expr = self.collect_expr_opt(e.expr());
818 if let Some(op) = e.op_kind() {
819 self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
820 } else {
821 self.alloc_expr(Expr::Missing, syntax_ptr)
822 }
823 }
824 ast::Expr::LambdaExpr(e) => {
825 let mut args = Vec::new();
826 let mut arg_types = Vec::new();
827 if let Some(pl) = e.param_list() {
828 for param in pl.params() {
829 let pat = self.collect_pat_opt(param.pat());
830 let type_ref = param.ascribed_type().map(TypeRef::from_ast);
831 args.push(pat);
832 arg_types.push(type_ref);
833 }
834 }
835 let body = self.collect_expr_opt(e.body());
836 self.alloc_expr(Expr::Lambda { args, arg_types, body }, syntax_ptr)
837 }
838 ast::Expr::BinExpr(e) => {
839 let lhs = self.collect_expr_opt(e.lhs());
840 let rhs = self.collect_expr_opt(e.rhs());
841 let op = e.op_kind().map(BinaryOp::from);
842 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
843 }
844 ast::Expr::TupleExpr(e) => {
845 let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect();
846 self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr)
847 }
848
849 ast::Expr::ArrayExpr(e) => {
850 let kind = e.kind();
851
852 match kind {
853 ArrayExprKind::ElementList(e) => {
854 let exprs = e.map(|expr| self.collect_expr(expr)).collect();
855 self.alloc_expr(Expr::Array(Array::ElementList(exprs)), syntax_ptr)
856 }
857 ArrayExprKind::Repeat { initializer, repeat } => {
858 let initializer = self.collect_expr_opt(initializer);
859 let repeat = self.collect_expr_opt(repeat);
860 self.alloc_expr(
861 Expr::Array(Array::Repeat { initializer, repeat }),
862 syntax_ptr,
863 )
864 }
865 }
866 }
867
868 ast::Expr::Literal(e) => {
869 let lit = match e.kind() {
870 LiteralKind::IntNumber { suffix } => {
871 let known_name = suffix
872 .and_then(|it| IntTy::from_suffix(&it).map(UncertainIntTy::Known));
873
874 Literal::Int(
875 Default::default(),
876 known_name.unwrap_or(UncertainIntTy::Unknown),
877 )
878 }
879 LiteralKind::FloatNumber { suffix } => {
880 let known_name = suffix
881 .and_then(|it| FloatTy::from_suffix(&it).map(UncertainFloatTy::Known));
882
883 Literal::Float(
884 Default::default(),
885 known_name.unwrap_or(UncertainFloatTy::Unknown),
886 )
887 }
888 LiteralKind::ByteString => Literal::ByteString(Default::default()),
889 LiteralKind::String => Literal::String(Default::default()),
890 LiteralKind::Byte => {
891 Literal::Int(Default::default(), UncertainIntTy::Known(IntTy::u8()))
892 }
893 LiteralKind::Bool => Literal::Bool(Default::default()),
894 LiteralKind::Char => Literal::Char(Default::default()),
895 };
896 self.alloc_expr(Expr::Literal(lit), syntax_ptr)
897 }
898 ast::Expr::IndexExpr(e) => {
899 let base = self.collect_expr_opt(e.base());
900 let index = self.collect_expr_opt(e.index());
901 self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
902 }
903
904 // FIXME implement HIR for these:
905 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
906 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
907 ast::Expr::MacroCall(e) => {
908 let ast_id = self
909 .db
910 .ast_id_map(self.current_file_id)
911 .ast_id(&e)
912 .with_file_id(self.current_file_id);
913
914 if let Some(path) = e.path().and_then(Path::from_ast) {
915 if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) {
916 let call_id = MacroCallLoc { def: def.id, ast_id }.id(self.db);
917 let file_id = call_id.as_file(MacroFileKind::Expr);
918 if let Some(node) = self.db.parse_or_expand(file_id) {
919 if let Some(expr) = ast::Expr::cast(node) {
920 log::debug!("macro expansion {:#?}", expr.syntax());
921 let old_file_id =
922 std::mem::replace(&mut self.current_file_id, file_id);
923 let id = self.collect_expr(expr);
924 self.current_file_id = old_file_id;
925 return id;
926 }
927 }
928 }
929 }
930 // FIXME: Instead of just dropping the error from expansion
931 // report it
932 self.alloc_expr(Expr::Missing, syntax_ptr)
933 }
934 }
935 }
936
937 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
938 if let Some(expr) = expr {
939 self.collect_expr(expr)
940 } else {
941 self.exprs.alloc(Expr::Missing)
942 }
943 }
944
945 fn collect_block(&mut self, block: ast::Block) -> ExprId {
946 let statements = block
947 .statements()
948 .map(|s| match s {
949 ast::Stmt::LetStmt(stmt) => {
950 let pat = self.collect_pat_opt(stmt.pat());
951 let type_ref = stmt.ascribed_type().map(TypeRef::from_ast);
952 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
953 Statement::Let { pat, type_ref, initializer }
954 }
955 ast::Stmt::ExprStmt(stmt) => Statement::Expr(self.collect_expr_opt(stmt.expr())),
956 })
957 .collect();
958 let tail = block.expr().map(|e| self.collect_expr(e));
959 self.alloc_expr(Expr::Block { statements, tail }, SyntaxNodePtr::new(block.syntax()))
960 }
961
962 fn collect_block_opt(&mut self, block: Option<ast::Block>) -> ExprId {
963 if let Some(block) = block {
964 self.collect_block(block)
965 } else {
966 self.exprs.alloc(Expr::Missing)
967 }
968 }
969
970 fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
971 let pattern = match &pat {
972 ast::Pat::BindPat(bp) => {
973 let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
974 let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref());
975 let subpat = bp.pat().map(|subpat| self.collect_pat(subpat));
976 Pat::Bind { name, mode: annotation, subpat }
977 }
978 ast::Pat::TupleStructPat(p) => {
979 let path = p.path().and_then(Path::from_ast);
980 let args = p.args().map(|p| self.collect_pat(p)).collect();
981 Pat::TupleStruct { path, args }
982 }
983 ast::Pat::RefPat(p) => {
984 let pat = self.collect_pat_opt(p.pat());
985 let mutability = Mutability::from_mutable(p.is_mut());
986 Pat::Ref { pat, mutability }
987 }
988 ast::Pat::PathPat(p) => {
989 let path = p.path().and_then(Path::from_ast);
990 path.map(Pat::Path).unwrap_or(Pat::Missing)
991 }
992 ast::Pat::TuplePat(p) => {
993 let args = p.args().map(|p| self.collect_pat(p)).collect();
994 Pat::Tuple(args)
995 }
996 ast::Pat::PlaceholderPat(_) => Pat::Wild,
997 ast::Pat::RecordPat(p) => {
998 let path = p.path().and_then(Path::from_ast);
999 let record_field_pat_list =
1000 p.record_field_pat_list().expect("every struct should have a field list");
1001 let mut fields: Vec<_> = record_field_pat_list
1002 .bind_pats()
1003 .filter_map(|bind_pat| {
1004 let ast_pat =
1005 ast::Pat::cast(bind_pat.syntax().clone()).expect("bind pat is a pat");
1006 let pat = self.collect_pat(ast_pat);
1007 let name = bind_pat.name()?.as_name();
1008 Some(RecordFieldPat { name, pat })
1009 })
1010 .collect();
1011 let iter = record_field_pat_list.record_field_pats().filter_map(|f| {
1012 let ast_pat = f.pat()?;
1013 let pat = self.collect_pat(ast_pat);
1014 let name = f.name()?.as_name();
1015 Some(RecordFieldPat { name, pat })
1016 });
1017 fields.extend(iter);
1018
1019 Pat::Struct { path, args: fields }
1020 }
1021
1022 // FIXME: implement
1023 ast::Pat::BoxPat(_) => Pat::Missing,
1024 ast::Pat::LiteralPat(_) => Pat::Missing,
1025 ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing,
1026 };
1027 let ptr = AstPtr::new(&pat);
1028 self.alloc_pat(pattern, Either::A(ptr))
1029 }
1030
1031 fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
1032 if let Some(pat) = pat {
1033 self.collect_pat(pat)
1034 } else {
1035 self.pats.alloc(Pat::Missing)
1036 }
1037 }
1038
1039 fn collect_const_body(&mut self, node: ast::ConstDef) {
1040 let body = self.collect_expr_opt(node.body());
1041 self.body_expr = Some(body);
1042 }
1043
1044 fn collect_static_body(&mut self, node: ast::StaticDef) {
1045 let body = self.collect_expr_opt(node.body());
1046 self.body_expr = Some(body);
1047 }
1048
1049 fn collect_fn_body(&mut self, node: ast::FnDef) {
1050 if let Some(param_list) = node.param_list() {
1051 if let Some(self_param) = param_list.self_param() {
1052 let ptr = AstPtr::new(&self_param);
1053 let param_pat = self.alloc_pat(
1054 Pat::Bind {
1055 name: SELF_PARAM,
1056 mode: BindingAnnotation::Unannotated,
1057 subpat: None,
1058 },
1059 Either::B(ptr),
1060 );
1061 self.params.push(param_pat);
1062 }
1063
1064 for param in param_list.params() {
1065 let pat = if let Some(pat) = param.pat() {
1066 pat
1067 } else {
1068 continue;
1069 };
1070 let param_pat = self.collect_pat(pat);
1071 self.params.push(param_pat);
1072 }
1073 };
1074
1075 let body = self.collect_block_opt(node.body());
1076 self.body_expr = Some(body);
1077 }
1078
1079 fn finish(self) -> (Body, BodySourceMap) {
1080 let body = Body {
1081 owner: self.owner,
1082 exprs: self.exprs,
1083 pats: self.pats,
1084 params: self.params,
1085 body_expr: self.body_expr.expect("A body should have been collected"),
1086 };
1087 (body, self.source_map)
1088 }
1089}
1090
1091impl From<ast::BinOp> for BinaryOp {
1092 fn from(ast_op: ast::BinOp) -> Self {
1093 match ast_op {
1094 ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or),
1095 ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And),
1096 ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
1097 ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: true }),
1098 ast::BinOp::LesserEqualTest => {
1099 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false })
1100 }
1101 ast::BinOp::GreaterEqualTest => {
1102 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false })
1103 }
1104 ast::BinOp::LesserTest => {
1105 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true })
1106 }
1107 ast::BinOp::GreaterTest => {
1108 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true })
1109 }
1110 ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add),
1111 ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul),
1112 ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub),
1113 ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div),
1114 ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem),
1115 ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl),
1116 ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr),
1117 ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor),
1118 ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr),
1119 ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd),
1120 ast::BinOp::Assignment => BinaryOp::Assignment { op: None },
1121 ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) },
1122 ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) },
1123 ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) },
1124 ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) },
1125 ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) },
1126 ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) },
1127 ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) },
1128 ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) },
1129 ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) },
1130 ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) },
1131 }
1132 }
1133}
1134
1135pub(crate) fn body_with_source_map_query( 538pub(crate) fn body_with_source_map_query(
1136 db: &impl HirDatabase, 539 db: &impl HirDatabase,
1137 def: DefWithBody, 540 def: DefWithBody,
1138) -> (Arc<Body>, Arc<BodySourceMap>) { 541) -> (Arc<Body>, Arc<BodySourceMap>) {
1139 let mut collector; 542 let mut params = None;
1140 543
1141 match def { 544 let (file_id, body) = match def {
1142 DefWithBody::Const(ref c) => { 545 DefWithBody::Function(f) => {
1143 let src = c.source(db);
1144 collector = ExprCollector::new(def, src.file_id, def.resolver(db), db);
1145 collector.collect_const_body(src.ast)
1146 }
1147 DefWithBody::Function(ref f) => {
1148 let src = f.source(db); 546 let src = f.source(db);
1149 collector = ExprCollector::new(def, src.file_id, def.resolver(db), db); 547 params = src.ast.param_list();
1150 collector.collect_fn_body(src.ast) 548 (src.file_id, src.ast.body().map(ast::Expr::from))
549 }
550 DefWithBody::Const(c) => {
551 let src = c.source(db);
552 (src.file_id, src.ast.body())
1151 } 553 }
1152 DefWithBody::Static(ref s) => { 554 DefWithBody::Static(s) => {
1153 let src = s.source(db); 555 let src = s.source(db);
1154 collector = ExprCollector::new(def, src.file_id, def.resolver(db), db); 556 (src.file_id, src.ast.body())
1155 collector.collect_static_body(src.ast)
1156 } 557 }
1157 } 558 };
1158 559
1159 let (body, source_map) = collector.finish(); 560 let (body, source_map) = lower::lower(db, def.resolver(db), file_id, def, params, body);
1160 (Arc::new(body), Arc::new(source_map)) 561 (Arc::new(body), Arc::new(source_map))
1161} 562}
1162 563
diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs
new file mode 100644
index 000000000..6afd80989
--- /dev/null
+++ b/crates/ra_hir/src/expr/lower.rs
@@ -0,0 +1,630 @@
1use ra_arena::Arena;
2use ra_syntax::{
3 ast::{
4 self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, NameOwner,
5 TypeAscriptionOwner,
6 },
7 AstNode, AstPtr,
8};
9use test_utils::tested_by;
10
11use crate::{
12 name::{AsName, Name, SELF_PARAM},
13 path::GenericArgs,
14 ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy},
15 type_ref::TypeRef,
16 DefWithBody, Either, HirDatabase, HirFileId, MacroCallLoc, MacroFileKind, Mutability, Path,
17 Resolver, Source,
18};
19
20use super::{
21 ArithOp, Array, BinaryOp, BindingAnnotation, Body, BodySourceMap, CmpOp, Expr, ExprId, Literal,
22 LogicOp, MatchArm, Ordering, Pat, PatId, PatPtr, RecordFieldPat, RecordLitField, Statement,
23};
24
25pub(super) fn lower(
26 db: &impl HirDatabase,
27 resolver: Resolver,
28 file_id: HirFileId,
29 owner: DefWithBody,
30 params: Option<ast::ParamList>,
31 body: Option<ast::Expr>,
32) -> (Body, BodySourceMap) {
33 ExprCollector {
34 resolver,
35 db,
36 original_file_id: file_id,
37 current_file_id: file_id,
38 source_map: BodySourceMap::default(),
39 body: Body {
40 owner,
41 exprs: Arena::default(),
42 pats: Arena::default(),
43 params: Vec::new(),
44 body_expr: ExprId((!0).into()),
45 },
46 }
47 .collect(params, body)
48}
49
50struct ExprCollector<DB> {
51 db: DB,
52 resolver: Resolver,
53 // Expr collector expands macros along the way. original points to the file
54 // we started with, current points to the current macro expansion. source
55 // maps don't support macros yet, so we only record info into source map if
56 // current == original (see #1196)
57 original_file_id: HirFileId,
58 current_file_id: HirFileId,
59
60 body: Body,
61 source_map: BodySourceMap,
62}
63
64impl<'a, DB> ExprCollector<&'a DB>
65where
66 DB: HirDatabase,
67{
68 fn collect(
69 mut self,
70 param_list: Option<ast::ParamList>,
71 body: Option<ast::Expr>,
72 ) -> (Body, BodySourceMap) {
73 if let Some(param_list) = param_list {
74 if let Some(self_param) = param_list.self_param() {
75 let ptr = AstPtr::new(&self_param);
76 let param_pat = self.alloc_pat(
77 Pat::Bind {
78 name: SELF_PARAM,
79 mode: BindingAnnotation::Unannotated,
80 subpat: None,
81 },
82 Either::B(ptr),
83 );
84 self.body.params.push(param_pat);
85 }
86
87 for param in param_list.params() {
88 let pat = match param.pat() {
89 None => continue,
90 Some(pat) => pat,
91 };
92 let param_pat = self.collect_pat(pat);
93 self.body.params.push(param_pat);
94 }
95 };
96
97 self.body.body_expr = self.collect_expr_opt(body);
98 (self.body, self.source_map)
99 }
100
101 fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
102 let ptr = Either::A(ptr);
103 let id = self.body.exprs.alloc(expr);
104 if self.current_file_id == self.original_file_id {
105 self.source_map.expr_map.insert(ptr, id);
106 }
107 self.source_map
108 .expr_map_back
109 .insert(id, Source { file_id: self.current_file_id, ast: ptr });
110 id
111 }
112 // desugared exprs don't have ptr, that's wrong and should be fixed
113 // somehow.
114 fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
115 self.body.exprs.alloc(expr)
116 }
117 fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId {
118 let ptr = Either::B(ptr);
119 let id = self.body.exprs.alloc(expr);
120 if self.current_file_id == self.original_file_id {
121 self.source_map.expr_map.insert(ptr, id);
122 }
123 self.source_map
124 .expr_map_back
125 .insert(id, Source { file_id: self.current_file_id, ast: ptr });
126 id
127 }
128 fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
129 let id = self.body.pats.alloc(pat);
130 if self.current_file_id == self.original_file_id {
131 self.source_map.pat_map.insert(ptr, id);
132 }
133 self.source_map.pat_map_back.insert(id, Source { file_id: self.current_file_id, ast: ptr });
134 id
135 }
136
137 fn empty_block(&mut self) -> ExprId {
138 let block = Expr::Block { statements: Vec::new(), tail: None };
139 self.body.exprs.alloc(block)
140 }
141
142 fn missing_expr(&mut self) -> ExprId {
143 self.body.exprs.alloc(Expr::Missing)
144 }
145
146 fn missing_pat(&mut self) -> PatId {
147 self.body.pats.alloc(Pat::Missing)
148 }
149
150 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
151 let syntax_ptr = AstPtr::new(&expr);
152 match expr {
153 ast::Expr::IfExpr(e) => {
154 let then_branch = self.collect_block_opt(e.then_branch());
155
156 let else_branch = e.else_branch().map(|b| match b {
157 ast::ElseBranch::Block(it) => self.collect_block(it),
158 ast::ElseBranch::IfExpr(elif) => {
159 let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap();
160 self.collect_expr(expr)
161 }
162 });
163
164 let condition = match e.condition() {
165 None => self.missing_expr(),
166 Some(condition) => match condition.pat() {
167 None => self.collect_expr_opt(condition.expr()),
168 // if let -- desugar to match
169 Some(pat) => {
170 let pat = self.collect_pat(pat);
171 let match_expr = self.collect_expr_opt(condition.expr());
172 let placeholder_pat = self.missing_pat();
173 let arms = vec![
174 MatchArm { pats: vec![pat], expr: then_branch, guard: None },
175 MatchArm {
176 pats: vec![placeholder_pat],
177 expr: else_branch.unwrap_or_else(|| self.empty_block()),
178 guard: None,
179 },
180 ];
181 return self
182 .alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr);
183 }
184 },
185 };
186
187 self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
188 }
189 ast::Expr::TryBlockExpr(e) => {
190 let body = self.collect_block_opt(e.body());
191 self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
192 }
193 ast::Expr::BlockExpr(e) => self.collect_block(e),
194 ast::Expr::LoopExpr(e) => {
195 let body = self.collect_block_opt(e.loop_body());
196 self.alloc_expr(Expr::Loop { body }, syntax_ptr)
197 }
198 ast::Expr::WhileExpr(e) => {
199 let body = self.collect_block_opt(e.loop_body());
200
201 let condition = match e.condition() {
202 None => self.missing_expr(),
203 Some(condition) => match condition.pat() {
204 None => self.collect_expr_opt(condition.expr()),
205 // if let -- desugar to match
206 Some(pat) => {
207 tested_by!(infer_while_let);
208 let pat = self.collect_pat(pat);
209 let match_expr = self.collect_expr_opt(condition.expr());
210 let placeholder_pat = self.missing_pat();
211 let break_ = self.alloc_expr_desugared(Expr::Break { expr: None });
212 let arms = vec![
213 MatchArm { pats: vec![pat], expr: body, guard: None },
214 MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None },
215 ];
216 let match_expr =
217 self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms });
218 return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr);
219 }
220 },
221 };
222
223 self.alloc_expr(Expr::While { condition, body }, syntax_ptr)
224 }
225 ast::Expr::ForExpr(e) => {
226 let iterable = self.collect_expr_opt(e.iterable());
227 let pat = self.collect_pat_opt(e.pat());
228 let body = self.collect_block_opt(e.loop_body());
229 self.alloc_expr(Expr::For { iterable, pat, body }, syntax_ptr)
230 }
231 ast::Expr::CallExpr(e) => {
232 let callee = self.collect_expr_opt(e.expr());
233 let args = if let Some(arg_list) = e.arg_list() {
234 arg_list.args().map(|e| self.collect_expr(e)).collect()
235 } else {
236 Vec::new()
237 };
238 self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
239 }
240 ast::Expr::MethodCallExpr(e) => {
241 let receiver = self.collect_expr_opt(e.expr());
242 let args = if let Some(arg_list) = e.arg_list() {
243 arg_list.args().map(|e| self.collect_expr(e)).collect()
244 } else {
245 Vec::new()
246 };
247 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
248 let generic_args = e.type_arg_list().and_then(GenericArgs::from_ast);
249 self.alloc_expr(
250 Expr::MethodCall { receiver, method_name, args, generic_args },
251 syntax_ptr,
252 )
253 }
254 ast::Expr::MatchExpr(e) => {
255 let expr = self.collect_expr_opt(e.expr());
256 let arms = if let Some(match_arm_list) = e.match_arm_list() {
257 match_arm_list
258 .arms()
259 .map(|arm| MatchArm {
260 pats: arm.pats().map(|p| self.collect_pat(p)).collect(),
261 expr: self.collect_expr_opt(arm.expr()),
262 guard: arm
263 .guard()
264 .and_then(|guard| guard.expr())
265 .map(|e| self.collect_expr(e)),
266 })
267 .collect()
268 } else {
269 Vec::new()
270 };
271 self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
272 }
273 ast::Expr::PathExpr(e) => {
274 let path =
275 e.path().and_then(Path::from_ast).map(Expr::Path).unwrap_or(Expr::Missing);
276 self.alloc_expr(path, syntax_ptr)
277 }
278 ast::Expr::ContinueExpr(_e) => {
279 // FIXME: labels
280 self.alloc_expr(Expr::Continue, syntax_ptr)
281 }
282 ast::Expr::BreakExpr(e) => {
283 let expr = e.expr().map(|e| self.collect_expr(e));
284 self.alloc_expr(Expr::Break { expr }, syntax_ptr)
285 }
286 ast::Expr::ParenExpr(e) => {
287 let inner = self.collect_expr_opt(e.expr());
288 // make the paren expr point to the inner expression as well
289 self.source_map.expr_map.insert(Either::A(syntax_ptr), inner);
290 inner
291 }
292 ast::Expr::ReturnExpr(e) => {
293 let expr = e.expr().map(|e| self.collect_expr(e));
294 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
295 }
296 ast::Expr::RecordLit(e) => {
297 let path = e.path().and_then(Path::from_ast);
298 let mut field_ptrs = Vec::new();
299 let record_lit = if let Some(nfl) = e.record_field_list() {
300 let fields = nfl
301 .fields()
302 .inspect(|field| field_ptrs.push(AstPtr::new(field)))
303 .map(|field| RecordLitField {
304 name: field
305 .name_ref()
306 .map(|nr| nr.as_name())
307 .unwrap_or_else(Name::missing),
308 expr: if let Some(e) = field.expr() {
309 self.collect_expr(e)
310 } else if let Some(nr) = field.name_ref() {
311 // field shorthand
312 self.alloc_expr_field_shorthand(
313 Expr::Path(Path::from_name_ref(&nr)),
314 AstPtr::new(&field),
315 )
316 } else {
317 self.missing_expr()
318 },
319 })
320 .collect();
321 let spread = nfl.spread().map(|s| self.collect_expr(s));
322 Expr::RecordLit { path, fields, spread }
323 } else {
324 Expr::RecordLit { path, fields: Vec::new(), spread: None }
325 };
326
327 let res = self.alloc_expr(record_lit, syntax_ptr);
328 for (i, ptr) in field_ptrs.into_iter().enumerate() {
329 self.source_map.field_map.insert((res, i), ptr);
330 }
331 res
332 }
333 ast::Expr::FieldExpr(e) => {
334 let expr = self.collect_expr_opt(e.expr());
335 let name = match e.field_access() {
336 Some(kind) => kind.as_name(),
337 _ => Name::missing(),
338 };
339 self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
340 }
341 ast::Expr::AwaitExpr(e) => {
342 let expr = self.collect_expr_opt(e.expr());
343 self.alloc_expr(Expr::Await { expr }, syntax_ptr)
344 }
345 ast::Expr::TryExpr(e) => {
346 let expr = self.collect_expr_opt(e.expr());
347 self.alloc_expr(Expr::Try { expr }, syntax_ptr)
348 }
349 ast::Expr::CastExpr(e) => {
350 let expr = self.collect_expr_opt(e.expr());
351 let type_ref = TypeRef::from_ast_opt(e.type_ref());
352 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
353 }
354 ast::Expr::RefExpr(e) => {
355 let expr = self.collect_expr_opt(e.expr());
356 let mutability = Mutability::from_mutable(e.is_mut());
357 self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr)
358 }
359 ast::Expr::PrefixExpr(e) => {
360 let expr = self.collect_expr_opt(e.expr());
361 if let Some(op) = e.op_kind() {
362 self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
363 } else {
364 self.alloc_expr(Expr::Missing, syntax_ptr)
365 }
366 }
367 ast::Expr::LambdaExpr(e) => {
368 let mut args = Vec::new();
369 let mut arg_types = Vec::new();
370 if let Some(pl) = e.param_list() {
371 for param in pl.params() {
372 let pat = self.collect_pat_opt(param.pat());
373 let type_ref = param.ascribed_type().map(TypeRef::from_ast);
374 args.push(pat);
375 arg_types.push(type_ref);
376 }
377 }
378 let body = self.collect_expr_opt(e.body());
379 self.alloc_expr(Expr::Lambda { args, arg_types, body }, syntax_ptr)
380 }
381 ast::Expr::BinExpr(e) => {
382 let lhs = self.collect_expr_opt(e.lhs());
383 let rhs = self.collect_expr_opt(e.rhs());
384 let op = e.op_kind().map(BinaryOp::from);
385 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
386 }
387 ast::Expr::TupleExpr(e) => {
388 let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect();
389 self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr)
390 }
391
392 ast::Expr::ArrayExpr(e) => {
393 let kind = e.kind();
394
395 match kind {
396 ArrayExprKind::ElementList(e) => {
397 let exprs = e.map(|expr| self.collect_expr(expr)).collect();
398 self.alloc_expr(Expr::Array(Array::ElementList(exprs)), syntax_ptr)
399 }
400 ArrayExprKind::Repeat { initializer, repeat } => {
401 let initializer = self.collect_expr_opt(initializer);
402 let repeat = self.collect_expr_opt(repeat);
403 self.alloc_expr(
404 Expr::Array(Array::Repeat { initializer, repeat }),
405 syntax_ptr,
406 )
407 }
408 }
409 }
410
411 ast::Expr::Literal(e) => {
412 let lit = match e.kind() {
413 LiteralKind::IntNumber { suffix } => {
414 let known_name = suffix
415 .and_then(|it| IntTy::from_suffix(&it).map(UncertainIntTy::Known));
416
417 Literal::Int(
418 Default::default(),
419 known_name.unwrap_or(UncertainIntTy::Unknown),
420 )
421 }
422 LiteralKind::FloatNumber { suffix } => {
423 let known_name = suffix
424 .and_then(|it| FloatTy::from_suffix(&it).map(UncertainFloatTy::Known));
425
426 Literal::Float(
427 Default::default(),
428 known_name.unwrap_or(UncertainFloatTy::Unknown),
429 )
430 }
431 LiteralKind::ByteString => Literal::ByteString(Default::default()),
432 LiteralKind::String => Literal::String(Default::default()),
433 LiteralKind::Byte => {
434 Literal::Int(Default::default(), UncertainIntTy::Known(IntTy::u8()))
435 }
436 LiteralKind::Bool => Literal::Bool(Default::default()),
437 LiteralKind::Char => Literal::Char(Default::default()),
438 };
439 self.alloc_expr(Expr::Literal(lit), syntax_ptr)
440 }
441 ast::Expr::IndexExpr(e) => {
442 let base = self.collect_expr_opt(e.base());
443 let index = self.collect_expr_opt(e.index());
444 self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
445 }
446
447 // FIXME implement HIR for these:
448 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
449 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
450 ast::Expr::MacroCall(e) => {
451 let ast_id = self
452 .db
453 .ast_id_map(self.current_file_id)
454 .ast_id(&e)
455 .with_file_id(self.current_file_id);
456
457 if let Some(path) = e.path().and_then(Path::from_ast) {
458 if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) {
459 let call_id = MacroCallLoc { def: def.id, ast_id }.id(self.db);
460 let file_id = call_id.as_file(MacroFileKind::Expr);
461 if let Some(node) = self.db.parse_or_expand(file_id) {
462 if let Some(expr) = ast::Expr::cast(node) {
463 log::debug!("macro expansion {:#?}", expr.syntax());
464 let old_file_id =
465 std::mem::replace(&mut self.current_file_id, file_id);
466 let id = self.collect_expr(expr);
467 self.current_file_id = old_file_id;
468 return id;
469 }
470 }
471 }
472 }
473 // FIXME: Instead of just dropping the error from expansion
474 // report it
475 self.alloc_expr(Expr::Missing, syntax_ptr)
476 }
477 }
478 }
479
480 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
481 if let Some(expr) = expr {
482 self.collect_expr(expr)
483 } else {
484 self.missing_expr()
485 }
486 }
487
488 fn collect_block(&mut self, expr: ast::BlockExpr) -> ExprId {
489 let syntax_node_ptr = AstPtr::new(&expr.clone().into());
490 let block = match expr.block() {
491 Some(block) => block,
492 None => return self.alloc_expr(Expr::Missing, syntax_node_ptr),
493 };
494 let statements = block
495 .statements()
496 .map(|s| match s {
497 ast::Stmt::LetStmt(stmt) => {
498 let pat = self.collect_pat_opt(stmt.pat());
499 let type_ref = stmt.ascribed_type().map(TypeRef::from_ast);
500 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
501 Statement::Let { pat, type_ref, initializer }
502 }
503 ast::Stmt::ExprStmt(stmt) => Statement::Expr(self.collect_expr_opt(stmt.expr())),
504 })
505 .collect();
506 let tail = block.expr().map(|e| self.collect_expr(e));
507 self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr)
508 }
509
510 fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
511 if let Some(block) = expr {
512 self.collect_block(block)
513 } else {
514 self.missing_expr()
515 }
516 }
517
518 fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
519 let pattern = match &pat {
520 ast::Pat::BindPat(bp) => {
521 let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
522 let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref());
523 let subpat = bp.pat().map(|subpat| self.collect_pat(subpat));
524 Pat::Bind { name, mode: annotation, subpat }
525 }
526 ast::Pat::TupleStructPat(p) => {
527 let path = p.path().and_then(Path::from_ast);
528 let args = p.args().map(|p| self.collect_pat(p)).collect();
529 Pat::TupleStruct { path, args }
530 }
531 ast::Pat::RefPat(p) => {
532 let pat = self.collect_pat_opt(p.pat());
533 let mutability = Mutability::from_mutable(p.is_mut());
534 Pat::Ref { pat, mutability }
535 }
536 ast::Pat::PathPat(p) => {
537 let path = p.path().and_then(Path::from_ast);
538 path.map(Pat::Path).unwrap_or(Pat::Missing)
539 }
540 ast::Pat::TuplePat(p) => {
541 let args = p.args().map(|p| self.collect_pat(p)).collect();
542 Pat::Tuple(args)
543 }
544 ast::Pat::PlaceholderPat(_) => Pat::Wild,
545 ast::Pat::RecordPat(p) => {
546 let path = p.path().and_then(Path::from_ast);
547 let record_field_pat_list =
548 p.record_field_pat_list().expect("every struct should have a field list");
549 let mut fields: Vec<_> = record_field_pat_list
550 .bind_pats()
551 .filter_map(|bind_pat| {
552 let ast_pat =
553 ast::Pat::cast(bind_pat.syntax().clone()).expect("bind pat is a pat");
554 let pat = self.collect_pat(ast_pat);
555 let name = bind_pat.name()?.as_name();
556 Some(RecordFieldPat { name, pat })
557 })
558 .collect();
559 let iter = record_field_pat_list.record_field_pats().filter_map(|f| {
560 let ast_pat = f.pat()?;
561 let pat = self.collect_pat(ast_pat);
562 let name = f.name()?.as_name();
563 Some(RecordFieldPat { name, pat })
564 });
565 fields.extend(iter);
566
567 Pat::Record { path, args: fields }
568 }
569
570 // FIXME: implement
571 ast::Pat::BoxPat(_) => Pat::Missing,
572 ast::Pat::LiteralPat(_) => Pat::Missing,
573 ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing,
574 };
575 let ptr = AstPtr::new(&pat);
576 self.alloc_pat(pattern, Either::A(ptr))
577 }
578
579 fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
580 if let Some(pat) = pat {
581 self.collect_pat(pat)
582 } else {
583 self.missing_pat()
584 }
585 }
586}
587
588impl From<ast::BinOp> for BinaryOp {
589 fn from(ast_op: ast::BinOp) -> Self {
590 match ast_op {
591 ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or),
592 ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And),
593 ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
594 ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: true }),
595 ast::BinOp::LesserEqualTest => {
596 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false })
597 }
598 ast::BinOp::GreaterEqualTest => {
599 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false })
600 }
601 ast::BinOp::LesserTest => {
602 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true })
603 }
604 ast::BinOp::GreaterTest => {
605 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true })
606 }
607 ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add),
608 ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul),
609 ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub),
610 ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div),
611 ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem),
612 ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl),
613 ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr),
614 ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor),
615 ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr),
616 ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd),
617 ast::BinOp::Assignment => BinaryOp::Assignment { op: None },
618 ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) },
619 ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) },
620 ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) },
621 ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) },
622 ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) },
623 ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) },
624 ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) },
625 ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) },
626 ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) },
627 ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) },
628 }
629 }
630}
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs
index 79e1857f9..b6d7f3fc1 100644
--- a/crates/ra_hir/src/expr/scope.rs
+++ b/crates/ra_hir/src/expr/scope.rs
@@ -172,7 +172,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
172#[cfg(test)] 172#[cfg(test)]
173mod tests { 173mod tests {
174 use ra_db::SourceDatabase; 174 use ra_db::SourceDatabase;
175 use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNodePtr}; 175 use ra_syntax::{algo::find_node_at_offset, ast, AstNode};
176 use test_utils::{assert_eq_text, extract_offset}; 176 use test_utils::{assert_eq_text, extract_offset};
177 177
178 use crate::{mock::MockDatabase, source_binder::SourceAnalyzer}; 178 use crate::{mock::MockDatabase, source_binder::SourceAnalyzer};
@@ -194,8 +194,7 @@ mod tests {
194 let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None); 194 let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None);
195 195
196 let scopes = analyzer.scopes(); 196 let scopes = analyzer.scopes();
197 let expr_id = 197 let expr_id = analyzer.body_source_map().node_expr(&marker.into()).unwrap();
198 analyzer.body_source_map().syntax_expr(SyntaxNodePtr::new(marker.syntax())).unwrap();
199 let scope = scopes.scope_for(expr_id); 198 let scope = scopes.scope_for(expr_id);
200 199
201 let actual = scopes 200 let actual = scopes
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs
index c8ae19869..1202913e2 100644
--- a/crates/ra_hir/src/expr/validation.rs
+++ b/crates/ra_hir/src/expr/validation.rs
@@ -1,9 +1,8 @@
1use rustc_hash::FxHashSet;
2use std::sync::Arc; 1use std::sync::Arc;
3 2
4use ra_syntax::ast::{AstNode, RecordLit}; 3use ra_syntax::ast;
4use rustc_hash::FxHashSet;
5 5
6use super::{Expr, ExprId, RecordLitField};
7use crate::{ 6use crate::{
8 adt::AdtDef, 7 adt::AdtDef,
9 diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, 8 diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr},
@@ -11,9 +10,10 @@ use crate::{
11 name, 10 name,
12 path::{PathKind, PathSegment}, 11 path::{PathKind, PathSegment},
13 ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, 12 ty::{ApplicationTy, InferenceResult, Ty, TypeCtor},
14 Function, HasSource, HirDatabase, ModuleDef, Name, Path, PerNs, Resolution, 13 Function, HirDatabase, ModuleDef, Name, Path, PerNs, Resolution,
15}; 14};
16use ra_syntax::ast; 15
16use super::{Expr, ExprId, RecordLitField};
17 17
18pub(crate) struct ExprValidator<'a, 'b: 'a> { 18pub(crate) struct ExprValidator<'a, 'b: 'a> {
19 func: Function, 19 func: Function,
@@ -79,21 +79,20 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
79 return; 79 return;
80 } 80 }
81 let source_map = self.func.body_source_map(db); 81 let source_map = self.func.body_source_map(db);
82 let file_id = self.func.source(db).file_id; 82
83 let parse = db.parse(file_id.original_file(db)); 83 if let Some(source_ptr) = source_map.expr_syntax(id) {
84 let source_file = parse.tree(); 84 if let Some(expr) = source_ptr.ast.a() {
85 if let Some(field_list_node) = source_map 85 let root = source_ptr.file_syntax(db);
86 .expr_syntax(id) 86 if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) {
87 .map(|ptr| ptr.to_node(source_file.syntax())) 87 if let Some(field_list) = record_lit.record_field_list() {
88 .and_then(RecordLit::cast) 88 self.sink.push(MissingFields {
89 .and_then(|lit| lit.record_field_list()) 89 file: source_ptr.file_id,
90 { 90 field_list: AstPtr::new(&field_list),
91 let field_list_ptr = AstPtr::new(&field_list_node); 91 missed_fields,
92 self.sink.push(MissingFields { 92 })
93 file: file_id, 93 }
94 field_list: field_list_ptr, 94 }
95 missed_fields, 95 }
96 })
97 } 96 }
98 } 97 }
99 98
@@ -133,10 +132,11 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
133 132
134 if params.len() == 2 && &params[0] == &mismatch.actual { 133 if params.len() == 2 && &params[0] == &mismatch.actual {
135 let source_map = self.func.body_source_map(db); 134 let source_map = self.func.body_source_map(db);
136 let file_id = self.func.source(db).file_id;
137 135
138 if let Some(expr) = source_map.expr_syntax(id).and_then(|n| n.cast::<ast::Expr>()) { 136 if let Some(source_ptr) = source_map.expr_syntax(id) {
139 self.sink.push(MissingOkInTailExpr { file: file_id, expr }); 137 if let Some(expr) = source_ptr.ast.a() {
138 self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr });
139 }
140 } 140 }
141 } 141 }
142 } 142 }
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 018fcd096..c3e589921 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -69,14 +69,16 @@ pub use self::{
69 resolve::Resolution, 69 resolve::Resolution,
70 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, 70 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer},
71 source_id::{AstIdMap, ErasedFileAstId}, 71 source_id::{AstIdMap, ErasedFileAstId},
72 ty::{display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor}, 72 ty::{
73 display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
74 },
73 type_ref::Mutability, 75 type_ref::Mutability,
74}; 76};
75 77
76pub use self::code_model::{ 78pub use self::code_model::{
77 docs::{DocDef, Docs, Documentation}, 79 docs::{DocDef, Docs, Documentation},
78 src::{HasSource, Source}, 80 src::{HasBodySource, HasSource, Source},
79 BuiltinType, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, 81 BuiltinType, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum,
80 EnumVariant, FieldSource, FnData, Function, MacroDef, Module, ModuleDef, ModuleSource, Static, 82 EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef, ModuleSource,
81 Struct, StructField, Trait, TypeAlias, Union, 83 Static, Struct, StructField, Trait, TypeAlias, Union,
82}; 84};
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index 5ee71e421..24316fc91 100644
--- a/crates/ra_hir/src/path.rs
+++ b/crates/ra_hir/src/path.rs
@@ -31,7 +31,8 @@ pub struct GenericArgs {
31 /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type 31 /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type
32 /// is left out. 32 /// is left out.
33 pub has_self_type: bool, 33 pub has_self_type: bool,
34 // someday also bindings 34 /// Associated type bindings like in `Iterator<Item = T>`.
35 pub bindings: Vec<(Name, TypeRef)>,
35} 36}
36 37
37/// A single generic argument. 38/// A single generic argument.
@@ -170,16 +171,24 @@ impl GenericArgs {
170 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref()); 171 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref());
171 args.push(GenericArg::Type(type_ref)); 172 args.push(GenericArg::Type(type_ref));
172 } 173 }
173 // lifetimes and assoc type args ignored for now 174 // lifetimes ignored for now
174 if !args.is_empty() { 175 let mut bindings = Vec::new();
175 Some(GenericArgs { args, has_self_type: false }) 176 for assoc_type_arg in node.assoc_type_args() {
176 } else { 177 if let Some(name_ref) = assoc_type_arg.name_ref() {
178 let name = name_ref.as_name();
179 let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref());
180 bindings.push((name, type_ref));
181 }
182 }
183 if args.is_empty() && bindings.is_empty() {
177 None 184 None
185 } else {
186 Some(GenericArgs { args, has_self_type: false, bindings })
178 } 187 }
179 } 188 }
180 189
181 pub(crate) fn empty() -> GenericArgs { 190 pub(crate) fn empty() -> GenericArgs {
182 GenericArgs { args: Vec::new(), has_self_type: false } 191 GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() }
183 } 192 }
184} 193}
185 194
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 56ff7da3a..fdbe5e8b0 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -27,9 +27,9 @@ use crate::{
27 name, 27 name,
28 path::{PathKind, PathSegment}, 28 path::{PathKind, PathSegment},
29 ty::method_resolution::implements_trait, 29 ty::method_resolution::implements_trait,
30 AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HirDatabase, HirFileId, 30 AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HasBody, HirDatabase,
31 MacroDef, Module, ModuleDef, Name, Path, PerNs, Resolution, Resolver, Static, Struct, Trait, 31 HirFileId, MacroDef, Module, ModuleDef, Name, Path, PerNs, Resolution, Resolver, Static,
32 Ty, 32 Struct, Trait, Ty,
33}; 33};
34 34
35/// Locates the module by `FileId`. Picks topmost module in the file. 35/// Locates the module by `FileId`. Picks topmost module in the file.
@@ -228,7 +228,7 @@ impl SourceAnalyzer {
228 let scopes = db.expr_scopes(def); 228 let scopes = db.expr_scopes(def);
229 let scope = match offset { 229 let scope = match offset {
230 None => scope_for(&scopes, &source_map, &node), 230 None => scope_for(&scopes, &source_map, &node),
231 Some(offset) => scope_for_offset(&scopes, &source_map, offset), 231 Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset),
232 }; 232 };
233 let resolver = expr::resolver_for_scope(def.body(db), db, scope); 233 let resolver = expr::resolver_for_scope(def.body(db), db, scope);
234 SourceAnalyzer { 234 SourceAnalyzer {
@@ -330,6 +330,7 @@ impl SourceAnalyzer {
330 .body_source_map 330 .body_source_map
331 .as_ref()? 331 .as_ref()?
332 .pat_syntax(it)? 332 .pat_syntax(it)?
333 .ast // FIXME: ignoring file_id here is definitelly wrong
333 .map_a(|ptr| ptr.cast::<ast::BindPat>().unwrap()); 334 .map_a(|ptr| ptr.cast::<ast::BindPat>().unwrap());
334 PathResolution::LocalBinding(pat_ptr) 335 PathResolution::LocalBinding(pat_ptr)
335 } 336 }
@@ -354,7 +355,7 @@ impl SourceAnalyzer {
354 ret.and_then(|entry| { 355 ret.and_then(|entry| {
355 Some(ScopeEntryWithSyntax { 356 Some(ScopeEntryWithSyntax {
356 name: entry.name().clone(), 357 name: entry.name().clone(),
357 ptr: source_map.pat_syntax(entry.pat())?, 358 ptr: source_map.pat_syntax(entry.pat())?.ast,
358 }) 359 })
359 }) 360 })
360 } 361 }
@@ -462,25 +463,35 @@ fn scope_for(
462 node: &SyntaxNode, 463 node: &SyntaxNode,
463) -> Option<ScopeId> { 464) -> Option<ScopeId> {
464 node.ancestors() 465 node.ancestors()
465 .map(|it| SyntaxNodePtr::new(&it)) 466 .filter_map(ast::Expr::cast)
466 .filter_map(|ptr| source_map.syntax_expr(ptr)) 467 .filter_map(|it| source_map.node_expr(&it))
467 .find_map(|it| scopes.scope_for(it)) 468 .find_map(|it| scopes.scope_for(it))
468} 469}
469 470
470fn scope_for_offset( 471fn scope_for_offset(
471 scopes: &ExprScopes, 472 scopes: &ExprScopes,
472 source_map: &BodySourceMap, 473 source_map: &BodySourceMap,
474 file_id: HirFileId,
473 offset: TextUnit, 475 offset: TextUnit,
474) -> Option<ScopeId> { 476) -> Option<ScopeId> {
475 scopes 477 scopes
476 .scope_by_expr() 478 .scope_by_expr()
477 .iter() 479 .iter()
478 .filter_map(|(id, scope)| Some((source_map.expr_syntax(*id)?, scope))) 480 .filter_map(|(id, scope)| {
481 let source = source_map.expr_syntax(*id)?;
482 // FIXME: correctly handle macro expansion
483 if source.file_id != file_id {
484 return None;
485 }
486 let syntax_node_ptr =
487 source.ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr());
488 Some((syntax_node_ptr, scope))
489 })
479 // find containing scope 490 // find containing scope
480 .min_by_key(|(ptr, _scope)| { 491 .min_by_key(|(ptr, _scope)| {
481 (!(ptr.range().start() <= offset && offset <= ptr.range().end()), ptr.range().len()) 492 (!(ptr.range().start() <= offset && offset <= ptr.range().end()), ptr.range().len())
482 }) 493 })
483 .map(|(ptr, scope)| adjust(scopes, source_map, ptr, offset).unwrap_or(*scope)) 494 .map(|(ptr, scope)| adjust(scopes, source_map, ptr, file_id, offset).unwrap_or(*scope))
484} 495}
485 496
486// XXX: during completion, cursor might be outside of any particular 497// XXX: during completion, cursor might be outside of any particular
@@ -489,13 +500,23 @@ fn adjust(
489 scopes: &ExprScopes, 500 scopes: &ExprScopes,
490 source_map: &BodySourceMap, 501 source_map: &BodySourceMap,
491 ptr: SyntaxNodePtr, 502 ptr: SyntaxNodePtr,
503 file_id: HirFileId,
492 offset: TextUnit, 504 offset: TextUnit,
493) -> Option<ScopeId> { 505) -> Option<ScopeId> {
494 let r = ptr.range(); 506 let r = ptr.range();
495 let child_scopes = scopes 507 let child_scopes = scopes
496 .scope_by_expr() 508 .scope_by_expr()
497 .iter() 509 .iter()
498 .filter_map(|(id, scope)| Some((source_map.expr_syntax(*id)?, scope))) 510 .filter_map(|(id, scope)| {
511 let source = source_map.expr_syntax(*id)?;
512 // FIXME: correctly handle macro expansion
513 if source.file_id != file_id {
514 return None;
515 }
516 let syntax_node_ptr =
517 source.ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr());
518 Some((syntax_node_ptr, scope))
519 })
499 .map(|(ptr, scope)| (ptr.range(), scope)) 520 .map(|(ptr, scope)| (ptr.range(), scope))
500 .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r); 521 .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r);
501 522
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index b54c80318..a3df08827 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -120,12 +120,44 @@ pub struct ProjectionTy {
120 pub parameters: Substs, 120 pub parameters: Substs,
121} 121}
122 122
123impl ProjectionTy {
124 pub fn trait_ref(&self, db: &impl HirDatabase) -> TraitRef {
125 TraitRef {
126 trait_: self
127 .associated_ty
128 .parent_trait(db)
129 .expect("projection ty without parent trait"),
130 substs: self.parameters.clone(),
131 }
132 }
133}
134
135impl TypeWalk for ProjectionTy {
136 fn walk(&self, f: &mut impl FnMut(&Ty)) {
137 self.parameters.walk(f);
138 }
139
140 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
141 self.parameters.walk_mut(f);
142 }
143}
144
123#[derive(Clone, PartialEq, Eq, Debug, Hash)] 145#[derive(Clone, PartialEq, Eq, Debug, Hash)]
124pub struct UnselectedProjectionTy { 146pub struct UnselectedProjectionTy {
125 pub type_name: Name, 147 pub type_name: Name,
126 pub parameters: Substs, 148 pub parameters: Substs,
127} 149}
128 150
151impl TypeWalk for UnselectedProjectionTy {
152 fn walk(&self, f: &mut impl FnMut(&Ty)) {
153 self.parameters.walk(f);
154 }
155
156 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
157 self.parameters.walk_mut(f);
158 }
159}
160
129/// A type. 161/// A type.
130/// 162///
131/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents 163/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents
@@ -282,20 +314,14 @@ impl TraitRef {
282 pub fn self_ty(&self) -> &Ty { 314 pub fn self_ty(&self) -> &Ty {
283 &self.substs[0] 315 &self.substs[0]
284 } 316 }
317}
285 318
286 pub fn subst(mut self, substs: &Substs) -> TraitRef { 319impl TypeWalk for TraitRef {
287 self.substs.walk_mut(&mut |ty_mut| { 320 fn walk(&self, f: &mut impl FnMut(&Ty)) {
288 let ty = mem::replace(ty_mut, Ty::Unknown);
289 *ty_mut = ty.subst(substs);
290 });
291 self
292 }
293
294 pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
295 self.substs.walk(f); 321 self.substs.walk(f);
296 } 322 }
297 323
298 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 324 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
299 self.substs.walk_mut(f); 325 self.substs.walk_mut(f);
300 } 326 }
301} 327}
@@ -306,6 +332,8 @@ impl TraitRef {
306pub enum GenericPredicate { 332pub enum GenericPredicate {
307 /// The given trait needs to be implemented for its type parameters. 333 /// The given trait needs to be implemented for its type parameters.
308 Implemented(TraitRef), 334 Implemented(TraitRef),
335 /// An associated type bindings like in `Iterator<Item = T>`.
336 Projection(ProjectionPredicate),
309 /// We couldn't resolve the trait reference. (If some type parameters can't 337 /// We couldn't resolve the trait reference. (If some type parameters can't
310 /// be resolved, they will just be Unknown). 338 /// be resolved, they will just be Unknown).
311 Error, 339 Error,
@@ -319,25 +347,35 @@ impl GenericPredicate {
319 } 347 }
320 } 348 }
321 349
322 pub fn subst(self, substs: &Substs) -> GenericPredicate { 350 pub fn is_implemented(&self) -> bool {
323 match self { 351 match self {
324 GenericPredicate::Implemented(trait_ref) => { 352 GenericPredicate::Implemented(_) => true,
325 GenericPredicate::Implemented(trait_ref.subst(substs)) 353 _ => false,
326 }
327 GenericPredicate::Error => self,
328 } 354 }
329 } 355 }
330 356
331 pub fn walk(&self, f: &mut impl FnMut(&Ty)) { 357 pub fn trait_ref(&self, db: &impl HirDatabase) -> Option<TraitRef> {
358 match self {
359 GenericPredicate::Implemented(tr) => Some(tr.clone()),
360 GenericPredicate::Projection(proj) => Some(proj.projection_ty.trait_ref(db)),
361 GenericPredicate::Error => None,
362 }
363 }
364}
365
366impl TypeWalk for GenericPredicate {
367 fn walk(&self, f: &mut impl FnMut(&Ty)) {
332 match self { 368 match self {
333 GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f), 369 GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f),
370 GenericPredicate::Projection(projection_pred) => projection_pred.walk(f),
334 GenericPredicate::Error => {} 371 GenericPredicate::Error => {}
335 } 372 }
336 } 373 }
337 374
338 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 375 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
339 match self { 376 match self {
340 GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f), 377 GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f),
378 GenericPredicate::Projection(projection_pred) => projection_pred.walk_mut(f),
341 GenericPredicate::Error => {} 379 GenericPredicate::Error => {}
342 } 380 }
343 } 381 }
@@ -378,16 +416,16 @@ impl FnSig {
378 pub fn ret(&self) -> &Ty { 416 pub fn ret(&self) -> &Ty {
379 &self.params_and_return[self.params_and_return.len() - 1] 417 &self.params_and_return[self.params_and_return.len() - 1]
380 } 418 }
419}
381 420
382 /// Applies the given substitutions to all types in this signature and 421impl TypeWalk for FnSig {
383 /// returns the result. 422 fn walk(&self, f: &mut impl FnMut(&Ty)) {
384 pub fn subst(&self, substs: &Substs) -> FnSig { 423 for t in self.params_and_return.iter() {
385 let result: Vec<_> = 424 t.walk(f);
386 self.params_and_return.iter().map(|ty| ty.clone().subst(substs)).collect(); 425 }
387 FnSig { params_and_return: result.into() }
388 } 426 }
389 427
390 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 428 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
391 // Without an Arc::make_mut_slice, we can't avoid the clone here: 429 // Without an Arc::make_mut_slice, we can't avoid the clone here:
392 let mut v: Vec<_> = self.params_and_return.iter().cloned().collect(); 430 let mut v: Vec<_> = self.params_and_return.iter().cloned().collect();
393 for t in &mut v { 431 for t in &mut v {
@@ -411,64 +449,6 @@ impl Ty {
411 Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty()) 449 Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty())
412 } 450 }
413 451
414 pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
415 match self {
416 Ty::Apply(a_ty) => {
417 for t in a_ty.parameters.iter() {
418 t.walk(f);
419 }
420 }
421 Ty::Projection(p_ty) => {
422 for t in p_ty.parameters.iter() {
423 t.walk(f);
424 }
425 }
426 Ty::UnselectedProjection(p_ty) => {
427 for t in p_ty.parameters.iter() {
428 t.walk(f);
429 }
430 }
431 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
432 for p in predicates.iter() {
433 p.walk(f);
434 }
435 }
436 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
437 }
438 f(self);
439 }
440
441 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
442 match self {
443 Ty::Apply(a_ty) => {
444 a_ty.parameters.walk_mut(f);
445 }
446 Ty::Projection(p_ty) => {
447 p_ty.parameters.walk_mut(f);
448 }
449 Ty::UnselectedProjection(p_ty) => {
450 p_ty.parameters.walk_mut(f);
451 }
452 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
453 let mut v: Vec<_> = predicates.iter().cloned().collect();
454 for p in &mut v {
455 p.walk_mut(f);
456 }
457 *predicates = v.into();
458 }
459 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
460 }
461 f(self);
462 }
463
464 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Ty {
465 self.walk_mut(&mut |ty_mut| {
466 let ty = mem::replace(ty_mut, Ty::Unknown);
467 *ty_mut = f(ty);
468 });
469 self
470 }
471
472 pub fn as_reference(&self) -> Option<(&Ty, Mutability)> { 452 pub fn as_reference(&self) -> Option<(&Ty, Mutability)> {
473 match self { 453 match self {
474 Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => { 454 Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => {
@@ -544,10 +524,53 @@ impl Ty {
544 } 524 }
545 } 525 }
546 526
527 /// Returns the type parameters of this type if it has some (i.e. is an ADT
528 /// or function); so if `self` is `Option<u32>`, this returns the `u32`.
529 pub fn substs(&self) -> Option<Substs> {
530 match self {
531 Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()),
532 _ => None,
533 }
534 }
535
536 /// If this is an `impl Trait` or `dyn Trait`, returns that trait.
537 pub fn inherent_trait(&self) -> Option<Trait> {
538 match self {
539 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
540 predicates.iter().find_map(|pred| match pred {
541 GenericPredicate::Implemented(tr) => Some(tr.trait_),
542 _ => None,
543 })
544 }
545 _ => None,
546 }
547 }
548}
549
550/// This allows walking structures that contain types to do something with those
551/// types, similar to Chalk's `Fold` trait.
552pub trait TypeWalk {
553 fn walk(&self, f: &mut impl FnMut(&Ty));
554 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty));
555
556 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self
557 where
558 Self: Sized,
559 {
560 self.walk_mut(&mut |ty_mut| {
561 let ty = mem::replace(ty_mut, Ty::Unknown);
562 *ty_mut = f(ty);
563 });
564 self
565 }
566
547 /// Replaces type parameters in this type using the given `Substs`. (So e.g. 567 /// Replaces type parameters in this type using the given `Substs`. (So e.g.
548 /// if `self` is `&[T]`, where type parameter T has index 0, and the 568 /// if `self` is `&[T]`, where type parameter T has index 0, and the
549 /// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.) 569 /// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.)
550 pub fn subst(self, substs: &Substs) -> Ty { 570 fn subst(self, substs: &Substs) -> Self
571 where
572 Self: Sized,
573 {
551 self.fold(&mut |ty| match ty { 574 self.fold(&mut |ty| match ty {
552 Ty::Param { idx, name } => { 575 Ty::Param { idx, name } => {
553 substs.get(idx as usize).cloned().unwrap_or(Ty::Param { idx, name }) 576 substs.get(idx as usize).cloned().unwrap_or(Ty::Param { idx, name })
@@ -557,24 +580,21 @@ impl Ty {
557 } 580 }
558 581
559 /// Substitutes `Ty::Bound` vars (as opposed to type parameters). 582 /// Substitutes `Ty::Bound` vars (as opposed to type parameters).
560 pub fn subst_bound_vars(self, substs: &Substs) -> Ty { 583 fn subst_bound_vars(self, substs: &Substs) -> Self
584 where
585 Self: Sized,
586 {
561 self.fold(&mut |ty| match ty { 587 self.fold(&mut |ty| match ty {
562 Ty::Bound(idx) => substs.get(idx as usize).cloned().unwrap_or_else(|| Ty::Bound(idx)), 588 Ty::Bound(idx) => substs.get(idx as usize).cloned().unwrap_or_else(|| Ty::Bound(idx)),
563 ty => ty, 589 ty => ty,
564 }) 590 })
565 } 591 }
566 592
567 /// Returns the type parameters of this type if it has some (i.e. is an ADT
568 /// or function); so if `self` is `Option<u32>`, this returns the `u32`.
569 pub fn substs(&self) -> Option<Substs> {
570 match self {
571 Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()),
572 _ => None,
573 }
574 }
575
576 /// Shifts up `Ty::Bound` vars by `n`. 593 /// Shifts up `Ty::Bound` vars by `n`.
577 pub fn shift_bound_vars(self, n: i32) -> Ty { 594 fn shift_bound_vars(self, n: i32) -> Self
595 where
596 Self: Sized,
597 {
578 self.fold(&mut |ty| match ty { 598 self.fold(&mut |ty| match ty {
579 Ty::Bound(idx) => { 599 Ty::Bound(idx) => {
580 assert!(idx as i32 >= -n); 600 assert!(idx as i32 >= -n);
@@ -583,18 +603,57 @@ impl Ty {
583 ty => ty, 603 ty => ty,
584 }) 604 })
585 } 605 }
606}
586 607
587 /// If this is an `impl Trait` or `dyn Trait`, returns that trait. 608impl TypeWalk for Ty {
588 pub fn inherent_trait(&self) -> Option<Trait> { 609 fn walk(&self, f: &mut impl FnMut(&Ty)) {
610 match self {
611 Ty::Apply(a_ty) => {
612 for t in a_ty.parameters.iter() {
613 t.walk(f);
614 }
615 }
616 Ty::Projection(p_ty) => {
617 for t in p_ty.parameters.iter() {
618 t.walk(f);
619 }
620 }
621 Ty::UnselectedProjection(p_ty) => {
622 for t in p_ty.parameters.iter() {
623 t.walk(f);
624 }
625 }
626 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
627 for p in predicates.iter() {
628 p.walk(f);
629 }
630 }
631 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
632 }
633 f(self);
634 }
635
636 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
589 match self { 637 match self {
638 Ty::Apply(a_ty) => {
639 a_ty.parameters.walk_mut(f);
640 }
641 Ty::Projection(p_ty) => {
642 p_ty.parameters.walk_mut(f);
643 }
644 Ty::UnselectedProjection(p_ty) => {
645 p_ty.parameters.walk_mut(f);
646 }
590 Ty::Dyn(predicates) | Ty::Opaque(predicates) => { 647 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
591 predicates.iter().find_map(|pred| match pred { 648 let mut v: Vec<_> = predicates.iter().cloned().collect();
592 GenericPredicate::Implemented(tr) => Some(tr.trait_), 649 for p in &mut v {
593 _ => None, 650 p.walk_mut(f);
594 }) 651 }
652 *predicates = v.into();
595 } 653 }
596 _ => None, 654 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
597 } 655 }
656 f(self);
598 } 657 }
599} 658}
600 659
@@ -742,20 +801,66 @@ impl HirDisplay for Ty {
742 Ty::Opaque(_) => write!(f, "impl ")?, 801 Ty::Opaque(_) => write!(f, "impl ")?,
743 _ => unreachable!(), 802 _ => unreachable!(),
744 }; 803 };
745 // looping by hand here just to format the bounds in a slightly nicer way 804 // Note: This code is written to produce nice results (i.e.
805 // corresponding to surface Rust) for types that can occur in
806 // actual Rust. It will have weird results if the predicates
807 // aren't as expected (i.e. self types = $0, projection
808 // predicates for a certain trait come after the Implemented
809 // predicate for that trait).
746 let mut first = true; 810 let mut first = true;
811 let mut angle_open = false;
747 for p in predicates.iter() { 812 for p in predicates.iter() {
748 if !first {
749 write!(f, " + ")?;
750 }
751 first = false;
752 match p { 813 match p {
753 // don't show the $0 self type
754 GenericPredicate::Implemented(trait_ref) => { 814 GenericPredicate::Implemented(trait_ref) => {
755 trait_ref.hir_fmt_ext(f, false)? 815 if angle_open {
816 write!(f, ">")?;
817 }
818 if !first {
819 write!(f, " + ")?;
820 }
821 // We assume that the self type is $0 (i.e. the
822 // existential) here, which is the only thing that's
823 // possible in actual Rust, and hence don't print it
824 write!(
825 f,
826 "{}",
827 trait_ref.trait_.name(f.db).unwrap_or_else(Name::missing)
828 )?;
829 if trait_ref.substs.len() > 1 {
830 write!(f, "<")?;
831 f.write_joined(&trait_ref.substs[1..], ", ")?;
832 // there might be assoc type bindings, so we leave the angle brackets open
833 angle_open = true;
834 }
835 }
836 GenericPredicate::Projection(projection_pred) => {
837 // in types in actual Rust, these will always come
838 // after the corresponding Implemented predicate
839 if angle_open {
840 write!(f, ", ")?;
841 } else {
842 write!(f, "<")?;
843 angle_open = true;
844 }
845 let name = projection_pred.projection_ty.associated_ty.name(f.db);
846 write!(f, "{} = ", name)?;
847 projection_pred.ty.hir_fmt(f)?;
848 }
849 GenericPredicate::Error => {
850 if angle_open {
851 // impl Trait<X, {error}>
852 write!(f, ", ")?;
853 } else if !first {
854 // impl Trait + {error}
855 write!(f, " + ")?;
856 }
857 p.hir_fmt(f)?;
756 } 858 }
757 GenericPredicate::Error => p.hir_fmt(f)?,
758 } 859 }
860 first = false;
861 }
862 if angle_open {
863 write!(f, ">")?;
759 } 864 }
760 } 865 }
761 Ty::Unknown => write!(f, "{{unknown}}")?, 866 Ty::Unknown => write!(f, "{{unknown}}")?,
@@ -766,13 +871,12 @@ impl HirDisplay for Ty {
766} 871}
767 872
768impl TraitRef { 873impl TraitRef {
769 fn hir_fmt_ext( 874 fn hir_fmt_ext(&self, f: &mut HirFormatter<impl HirDatabase>, use_as: bool) -> fmt::Result {
770 &self, 875 self.substs[0].hir_fmt(f)?;
771 f: &mut HirFormatter<impl HirDatabase>, 876 if use_as {
772 with_self_ty: bool, 877 write!(f, " as ")?;
773 ) -> fmt::Result { 878 } else {
774 if with_self_ty { 879 write!(f, ": ")?;
775 write!(f, "{}: ", self.substs[0].display(f.db),)?;
776 } 880 }
777 write!(f, "{}", self.trait_.name(f.db).unwrap_or_else(Name::missing))?; 881 write!(f, "{}", self.trait_.name(f.db).unwrap_or_else(Name::missing))?;
778 if self.substs.len() > 1 { 882 if self.substs.len() > 1 {
@@ -786,7 +890,7 @@ impl TraitRef {
786 890
787impl HirDisplay for TraitRef { 891impl HirDisplay for TraitRef {
788 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { 892 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
789 self.hir_fmt_ext(f, true) 893 self.hir_fmt_ext(f, false)
790 } 894 }
791} 895}
792 896
@@ -800,6 +904,16 @@ impl HirDisplay for GenericPredicate {
800 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { 904 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
801 match self { 905 match self {
802 GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, 906 GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
907 GenericPredicate::Projection(projection_pred) => {
908 write!(f, "<")?;
909 projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?;
910 write!(
911 f,
912 ">::{} = {}",
913 projection_pred.projection_ty.associated_ty.name(f.db),
914 projection_pred.ty.display(f.db)
915 )?;
916 }
803 GenericPredicate::Error => write!(f, "{{error}}")?, 917 GenericPredicate::Error => write!(f, "{{error}}")?,
804 } 918 }
805 Ok(()) 919 Ok(())
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs
index 2535d4ae7..08f52a53b 100644
--- a/crates/ra_hir/src/ty/autoderef.rs
+++ b/crates/ra_hir/src/ty/autoderef.rs
@@ -7,7 +7,7 @@ use std::iter::successors;
7 7
8use log::{info, warn}; 8use log::{info, warn};
9 9
10use super::{traits::Solution, Canonical, Ty}; 10use super::{traits::Solution, Canonical, Ty, TypeWalk};
11use crate::{HasGenericParams, HirDatabase, Name, Resolver}; 11use crate::{HasGenericParams, HirDatabase, Name, Resolver};
12 12
13const AUTODEREF_RECURSION_LIMIT: usize = 10; 13const AUTODEREF_RECURSION_LIMIT: usize = 10;
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 812990426..ec3b7ffef 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -30,7 +30,7 @@ use super::{
30 autoderef, lower, method_resolution, op, primitive, 30 autoderef, lower, method_resolution, op, primitive,
31 traits::{Guidance, Obligation, ProjectionPredicate, Solution}, 31 traits::{Guidance, Obligation, ProjectionPredicate, Solution},
32 ApplicationTy, CallableDef, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, 32 ApplicationTy, CallableDef, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef,
33 Ty, TypableDef, TypeCtor, 33 Ty, TypableDef, TypeCtor, TypeWalk,
34}; 34};
35use crate::{ 35use crate::{
36 adt::VariantDef, 36 adt::VariantDef,
@@ -50,8 +50,8 @@ use crate::{
50 }, 50 },
51 ty::infer::diagnostics::InferenceDiagnostic, 51 ty::infer::diagnostics::InferenceDiagnostic,
52 type_ref::{Mutability, TypeRef}, 52 type_ref::{Mutability, TypeRef},
53 AdtDef, ConstData, DefWithBody, FnData, Function, HirDatabase, ImplItem, ModuleDef, Name, Path, 53 AdtDef, ConstData, DefWithBody, FnData, Function, HasBody, HirDatabase, ImplItem, ModuleDef,
54 StructField, 54 Name, Path, StructField,
55}; 55};
56 56
57mod unify; 57mod unify;
@@ -749,7 +749,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
749 let is_non_ref_pat = match &body[pat] { 749 let is_non_ref_pat = match &body[pat] {
750 Pat::Tuple(..) 750 Pat::Tuple(..)
751 | Pat::TupleStruct { .. } 751 | Pat::TupleStruct { .. }
752 | Pat::Struct { .. } 752 | Pat::Record { .. }
753 | Pat::Range { .. } 753 | Pat::Range { .. }
754 | Pat::Slice { .. } => true, 754 | Pat::Slice { .. } => true,
755 // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented. 755 // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented.
@@ -806,10 +806,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
806 let subty = self.infer_pat(*pat, expectation, default_bm); 806 let subty = self.infer_pat(*pat, expectation, default_bm);
807 Ty::apply_one(TypeCtor::Ref(*mutability), subty) 807 Ty::apply_one(TypeCtor::Ref(*mutability), subty)
808 } 808 }
809 Pat::TupleStruct { path: ref p, args: ref subpats } => { 809 Pat::TupleStruct { path: p, args: subpats } => {
810 self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm) 810 self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm)
811 } 811 }
812 Pat::Struct { path: ref p, args: ref fields } => { 812 Pat::Record { path: p, args: fields } => {
813 self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat) 813 self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat)
814 } 814 }
815 Pat::Path(path) => { 815 Pat::Path(path) => {
@@ -817,7 +817,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
817 let resolver = self.resolver.clone(); 817 let resolver = self.resolver.clone();
818 self.infer_path_expr(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown) 818 self.infer_path_expr(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown)
819 } 819 }
820 Pat::Bind { mode, name: _name, subpat } => { 820 Pat::Bind { mode, name: _, subpat } => {
821 let mode = if mode == &BindingAnnotation::Unannotated { 821 let mode = if mode == &BindingAnnotation::Unannotated {
822 default_bm 822 default_bm
823 } else { 823 } else {
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs
index e7e8825d1..9a0d2d8f9 100644
--- a/crates/ra_hir/src/ty/infer/unify.rs
+++ b/crates/ra_hir/src/ty/infer/unify.rs
@@ -3,7 +3,7 @@
3use super::{InferenceContext, Obligation}; 3use super::{InferenceContext, Obligation};
4use crate::db::HirDatabase; 4use crate::db::HirDatabase;
5use crate::ty::{ 5use crate::ty::{
6 Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, 6 Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, TypeWalk,
7}; 7};
8 8
9impl<'a, D: HirDatabase> InferenceContext<'a, D> { 9impl<'a, D: HirDatabase> InferenceContext<'a, D> {
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 47d161277..f6f0137cf 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -8,7 +8,10 @@
8use std::iter; 8use std::iter;
9use std::sync::Arc; 9use std::sync::Arc;
10 10
11use super::{FnSig, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor}; 11use super::{
12 FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
13 TypeWalk,
14};
12use crate::{ 15use crate::{
13 adt::VariantDef, 16 adt::VariantDef,
14 generics::HasGenericParams, 17 generics::HasGenericParams,
@@ -62,7 +65,9 @@ impl Ty {
62 let self_ty = Ty::Bound(0); 65 let self_ty = Ty::Bound(0);
63 let predicates = bounds 66 let predicates = bounds
64 .iter() 67 .iter()
65 .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())) 68 .flat_map(|b| {
69 GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())
70 })
66 .collect::<Vec<_>>(); 71 .collect::<Vec<_>>();
67 Ty::Dyn(predicates.into()) 72 Ty::Dyn(predicates.into())
68 } 73 }
@@ -70,7 +75,9 @@ impl Ty {
70 let self_ty = Ty::Bound(0); 75 let self_ty = Ty::Bound(0);
71 let predicates = bounds 76 let predicates = bounds
72 .iter() 77 .iter()
73 .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())) 78 .flat_map(|b| {
79 GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())
80 })
74 .collect::<Vec<_>>(); 81 .collect::<Vec<_>>();
75 Ty::Opaque(predicates.into()) 82 Ty::Opaque(predicates.into())
76 } 83 }
@@ -326,15 +333,6 @@ impl TraitRef {
326 TraitRef { trait_, substs } 333 TraitRef { trait_, substs }
327 } 334 }
328 335
329 pub(crate) fn from_where_predicate(
330 db: &impl HirDatabase,
331 resolver: &Resolver,
332 pred: &WherePredicate,
333 ) -> Option<TraitRef> {
334 let self_ty = Ty::from_hir(db, resolver, &pred.type_ref);
335 TraitRef::from_type_bound(db, resolver, &pred.bound, self_ty)
336 }
337
338 pub(crate) fn from_type_bound( 336 pub(crate) fn from_type_bound(
339 db: &impl HirDatabase, 337 db: &impl HirDatabase,
340 resolver: &Resolver, 338 resolver: &Resolver,
@@ -349,26 +347,58 @@ impl TraitRef {
349} 347}
350 348
351impl GenericPredicate { 349impl GenericPredicate {
352 pub(crate) fn from_where_predicate( 350 pub(crate) fn from_where_predicate<'a>(
353 db: &impl HirDatabase, 351 db: &'a impl HirDatabase,
354 resolver: &Resolver, 352 resolver: &'a Resolver,
355 where_predicate: &WherePredicate, 353 where_predicate: &'a WherePredicate,
356 ) -> GenericPredicate { 354 ) -> impl Iterator<Item = GenericPredicate> + 'a {
357 TraitRef::from_where_predicate(db, &resolver, where_predicate) 355 let self_ty = Ty::from_hir(db, resolver, &where_predicate.type_ref);
358 .map_or(GenericPredicate::Error, GenericPredicate::Implemented) 356 GenericPredicate::from_type_bound(db, resolver, &where_predicate.bound, self_ty)
359 } 357 }
360 358
361 pub(crate) fn from_type_bound( 359 pub(crate) fn from_type_bound<'a>(
362 db: &impl HirDatabase, 360 db: &'a impl HirDatabase,
363 resolver: &Resolver, 361 resolver: &'a Resolver,
364 bound: &TypeBound, 362 bound: &'a TypeBound,
365 self_ty: Ty, 363 self_ty: Ty,
366 ) -> GenericPredicate { 364 ) -> impl Iterator<Item = GenericPredicate> + 'a {
367 TraitRef::from_type_bound(db, &resolver, bound, self_ty) 365 let trait_ref = TraitRef::from_type_bound(db, &resolver, bound, self_ty);
368 .map_or(GenericPredicate::Error, GenericPredicate::Implemented) 366 iter::once(trait_ref.clone().map_or(GenericPredicate::Error, GenericPredicate::Implemented))
367 .chain(
368 trait_ref.into_iter().flat_map(move |tr| {
369 assoc_type_bindings_from_type_bound(db, resolver, bound, tr)
370 }),
371 )
369 } 372 }
370} 373}
371 374
375fn assoc_type_bindings_from_type_bound<'a>(
376 db: &'a impl HirDatabase,
377 resolver: &'a Resolver,
378 bound: &'a TypeBound,
379 trait_ref: TraitRef,