diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-11-13 06:57:13 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2019-11-13 06:57:13 +0000 |
commit | 6ca0d79cff8746ea4f0c8fb8645d14b8b81bc7fc (patch) | |
tree | d03397ce4ab1a3d4dc90582f611805c8b2c82a74 | |
parent | 3322d65addd9ec61b8c5bc055803f6549946da8b (diff) | |
parent | 70dd70b1fcbbbe2e60849412412ef05e7d31eb0a (diff) |
Merge #2225
2225: Reduce duplication between uncertain floats & ints r=matklad a=matklad
Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r-- | crates/ra_hir/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 28 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/expr.rs | 30 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/primitive.rs | 32 |
7 files changed, 55 insertions, 70 deletions
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 92d71b9e8..5ba847d35 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -77,9 +77,7 @@ pub use crate::{ | |||
77 | source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, | 77 | source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, |
78 | ty::{ | 78 | ty::{ |
79 | display::HirDisplay, | 79 | display::HirDisplay, |
80 | primitive::{ | 80 | primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain}, |
81 | FloatBitness, FloatTy, IntBitness, IntTy, Signedness, UncertainFloatTy, UncertainIntTy, | ||
82 | }, | ||
83 | ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk, | 81 | ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk, |
84 | }, | 82 | }, |
85 | }; | 83 | }; |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 6f24cfad6..ff6030ac4 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -21,7 +21,7 @@ use crate::{ | |||
21 | expr::ExprId, | 21 | expr::ExprId, |
22 | generics::{GenericParams, HasGenericParams}, | 22 | generics::{GenericParams, HasGenericParams}, |
23 | util::make_mut_slice, | 23 | util::make_mut_slice, |
24 | Adt, Crate, DefWithBody, Mutability, Name, Trait, TypeAlias, | 24 | Adt, Crate, DefWithBody, FloatTy, IntTy, Mutability, Name, Trait, TypeAlias, Uncertain, |
25 | }; | 25 | }; |
26 | use display::{HirDisplay, HirFormatter}; | 26 | use display::{HirDisplay, HirFormatter}; |
27 | 27 | ||
@@ -47,10 +47,10 @@ pub enum TypeCtor { | |||
47 | Char, | 47 | Char, |
48 | 48 | ||
49 | /// A primitive integer type. For example, `i32`. | 49 | /// A primitive integer type. For example, `i32`. |
50 | Int(primitive::UncertainIntTy), | 50 | Int(Uncertain<IntTy>), |
51 | 51 | ||
52 | /// A primitive floating-point type. For example, `f64`. | 52 | /// A primitive floating-point type. For example, `f64`. |
53 | Float(primitive::UncertainFloatTy), | 53 | Float(Uncertain<FloatTy>), |
54 | 54 | ||
55 | /// Structures, enumerations and unions. | 55 | /// Structures, enumerations and unions. |
56 | Adt(Adt), | 56 | Adt(Adt), |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index f17c6c614..c09260864 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -31,10 +31,10 @@ use ra_prof::profile; | |||
31 | use test_utils::tested_by; | 31 | use test_utils::tested_by; |
32 | 32 | ||
33 | use super::{ | 33 | use super::{ |
34 | lower, primitive, | 34 | lower, |
35 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, | 35 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, |
36 | ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypableDef, | 36 | ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypableDef, |
37 | TypeCtor, TypeWalk, | 37 | TypeCtor, TypeWalk, Uncertain, |
38 | }; | 38 | }; |
39 | use crate::{ | 39 | use crate::{ |
40 | adt::VariantDef, | 40 | adt::VariantDef, |
@@ -43,7 +43,7 @@ use crate::{ | |||
43 | expr::{BindingAnnotation, Body, ExprId, PatId}, | 43 | expr::{BindingAnnotation, Body, ExprId, PatId}, |
44 | resolve::{Resolver, TypeNs}, | 44 | resolve::{Resolver, TypeNs}, |
45 | ty::infer::diagnostics::InferenceDiagnostic, | 45 | ty::infer::diagnostics::InferenceDiagnostic, |
46 | Adt, AssocItem, ConstData, DefWithBody, FnData, Function, Path, StructField, | 46 | Adt, AssocItem, ConstData, DefWithBody, FloatTy, FnData, Function, IntTy, Path, StructField, |
47 | }; | 47 | }; |
48 | 48 | ||
49 | macro_rules! ty_app { | 49 | macro_rules! ty_app { |
@@ -358,14 +358,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
358 | fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { | 358 | fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { |
359 | match ty { | 359 | match ty { |
360 | Ty::Unknown => self.new_type_var(), | 360 | Ty::Unknown => self.new_type_var(), |
361 | Ty::Apply(ApplicationTy { | 361 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(Uncertain::Unknown), .. }) => { |
362 | ctor: TypeCtor::Int(primitive::UncertainIntTy::Unknown), | 362 | self.new_integer_var() |
363 | .. | 363 | } |
364 | }) => self.new_integer_var(), | 364 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(Uncertain::Unknown), .. }) => { |
365 | Ty::Apply(ApplicationTy { | 365 | self.new_float_var() |
366 | ctor: TypeCtor::Float(primitive::UncertainFloatTy::Unknown), | 366 | } |
367 | .. | ||
368 | }) => self.new_float_var(), | ||
369 | _ => ty, | 367 | _ => ty, |
370 | } | 368 | } |
371 | } | 369 | } |
@@ -684,12 +682,8 @@ impl InferTy { | |||
684 | fn fallback_value(self) -> Ty { | 682 | fn fallback_value(self) -> Ty { |
685 | match self { | 683 | match self { |
686 | InferTy::TypeVar(..) => Ty::Unknown, | 684 | InferTy::TypeVar(..) => Ty::Unknown, |
687 | InferTy::IntVar(..) => { | 685 | InferTy::IntVar(..) => Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::i32()))), |
688 | Ty::simple(TypeCtor::Int(primitive::UncertainIntTy::Known(primitive::IntTy::i32()))) | 686 | InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float(Uncertain::Known(FloatTy::f64()))), |
689 | } | ||
690 | InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float( | ||
691 | primitive::UncertainFloatTy::Known(primitive::FloatTy::f64()), | ||
692 | )), | ||
693 | InferTy::MaybeNeverTypeVar(..) => Ty::simple(TypeCtor::Never), | 687 | InferTy::MaybeNeverTypeVar(..) => Ty::simple(TypeCtor::Never), |
694 | } | 688 | } |
695 | } | 689 | } |
diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs index c6802487a..5e68a1678 100644 --- a/crates/ra_hir/src/ty/infer/expr.rs +++ b/crates/ra_hir/src/ty/infer/expr.rs | |||
@@ -3,7 +3,10 @@ | |||
3 | use std::iter::{repeat, repeat_with}; | 3 | use std::iter::{repeat, repeat_with}; |
4 | use std::sync::Arc; | 4 | use std::sync::Arc; |
5 | 5 | ||
6 | use hir_def::path::{GenericArg, GenericArgs}; | 6 | use hir_def::{ |
7 | builtin_type::Signedness, | ||
8 | path::{GenericArg, GenericArgs}, | ||
9 | }; | ||
7 | use hir_expand::name; | 10 | use hir_expand::name; |
8 | 11 | ||
9 | use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; | 12 | use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; |
@@ -12,8 +15,9 @@ use crate::{ | |||
12 | expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, | 15 | expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, |
13 | generics::{GenericParams, HasGenericParams}, | 16 | generics::{GenericParams, HasGenericParams}, |
14 | ty::{ | 17 | ty::{ |
15 | autoderef, method_resolution, op, primitive, CallableDef, InferTy, Mutability, Namespace, | 18 | autoderef, method_resolution, op, CallableDef, InferTy, IntTy, Mutability, Namespace, |
16 | Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, | 19 | Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, |
20 | Uncertain, | ||
17 | }, | 21 | }, |
18 | Adt, Name, | 22 | Adt, Name, |
19 | }; | 23 | }; |
@@ -337,13 +341,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
337 | UnaryOp::Neg => { | 341 | UnaryOp::Neg => { |
338 | match &inner_ty { | 342 | match &inner_ty { |
339 | Ty::Apply(a_ty) => match a_ty.ctor { | 343 | Ty::Apply(a_ty) => match a_ty.ctor { |
340 | TypeCtor::Int(primitive::UncertainIntTy::Unknown) | 344 | TypeCtor::Int(Uncertain::Unknown) |
341 | | TypeCtor::Int(primitive::UncertainIntTy::Known( | 345 | | TypeCtor::Int(Uncertain::Known(IntTy { |
342 | primitive::IntTy { | 346 | signedness: Signedness::Signed, |
343 | signedness: primitive::Signedness::Signed, | 347 | .. |
344 | .. | 348 | })) |
345 | }, | ||
346 | )) | ||
347 | | TypeCtor::Float(..) => inner_ty, | 349 | | TypeCtor::Float(..) => inner_ty, |
348 | _ => Ty::Unknown, | 350 | _ => Ty::Unknown, |
349 | }, | 351 | }, |
@@ -428,9 +430,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
428 | ); | 430 | ); |
429 | self.infer_expr( | 431 | self.infer_expr( |
430 | *repeat, | 432 | *repeat, |
431 | &Expectation::has_type(Ty::simple(TypeCtor::Int( | 433 | &Expectation::has_type(Ty::simple(TypeCtor::Int(Uncertain::Known( |
432 | primitive::UncertainIntTy::Known(primitive::IntTy::usize()), | 434 | IntTy::usize(), |
433 | ))), | 435 | )))), |
434 | ); | 436 | ); |
435 | } | 437 | } |
436 | } | 438 | } |
@@ -443,9 +445,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
443 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str)) | 445 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str)) |
444 | } | 446 | } |
445 | Literal::ByteString(..) => { | 447 | Literal::ByteString(..) => { |
446 | let byte_type = Ty::simple(TypeCtor::Int(primitive::UncertainIntTy::Known( | 448 | let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8()))); |
447 | primitive::IntTy::u8(), | ||
448 | ))); | ||
449 | let slice_type = Ty::apply_one(TypeCtor::Slice, byte_type); | 449 | let slice_type = Ty::apply_one(TypeCtor::Slice, byte_type); |
450 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), slice_type) | 450 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), slice_type) |
451 | } | 451 | } |
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 1832fcf50..de3c56097 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -25,7 +25,7 @@ use crate::{ | |||
25 | generics::{GenericDef, WherePredicate}, | 25 | generics::{GenericDef, WherePredicate}, |
26 | resolve::{Resolver, TypeNs}, | 26 | resolve::{Resolver, TypeNs}, |
27 | ty::{ | 27 | ty::{ |
28 | primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, | 28 | primitive::{FloatTy, IntTy, Uncertain}, |
29 | Adt, | 29 | Adt, |
30 | }, | 30 | }, |
31 | util::make_mut_slice, | 31 | util::make_mut_slice, |
@@ -674,20 +674,20 @@ impl From<BuiltinFloat> for FloatTy { | |||
674 | } | 674 | } |
675 | } | 675 | } |
676 | 676 | ||
677 | impl From<Option<BuiltinInt>> for UncertainIntTy { | 677 | impl From<Option<BuiltinInt>> for Uncertain<IntTy> { |
678 | fn from(t: Option<BuiltinInt>) -> Self { | 678 | fn from(t: Option<BuiltinInt>) -> Self { |
679 | match t { | 679 | match t { |
680 | None => UncertainIntTy::Unknown, | 680 | None => Uncertain::Unknown, |
681 | Some(t) => UncertainIntTy::Known(t.into()), | 681 | Some(t) => Uncertain::Known(t.into()), |
682 | } | 682 | } |
683 | } | 683 | } |
684 | } | 684 | } |
685 | 685 | ||
686 | impl From<Option<BuiltinFloat>> for UncertainFloatTy { | 686 | impl From<Option<BuiltinFloat>> for Uncertain<FloatTy> { |
687 | fn from(t: Option<BuiltinFloat>) -> Self { | 687 | fn from(t: Option<BuiltinFloat>) -> Self { |
688 | match t { | 688 | match t { |
689 | None => UncertainFloatTy::Unknown, | 689 | None => Uncertain::Unknown, |
690 | Some(t) => UncertainFloatTy::Known(t.into()), | 690 | Some(t) => Uncertain::Known(t.into()), |
691 | } | 691 | } |
692 | } | 692 | } |
693 | } | 693 | } |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 8c3d32d09..eb5ca6769 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -8,16 +8,17 @@ use arrayvec::ArrayVec; | |||
8 | use hir_def::CrateModuleId; | 8 | use hir_def::CrateModuleId; |
9 | use rustc_hash::FxHashMap; | 9 | use rustc_hash::FxHashMap; |
10 | 10 | ||
11 | use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; | ||
12 | use crate::{ | 11 | use crate::{ |
13 | db::HirDatabase, | 12 | db::HirDatabase, |
14 | impl_block::{ImplBlock, ImplId}, | 13 | impl_block::{ImplBlock, ImplId}, |
15 | resolve::Resolver, | 14 | resolve::Resolver, |
16 | ty::primitive::{FloatBitness, UncertainFloatTy, UncertainIntTy}, | 15 | ty::primitive::{FloatBitness, Uncertain}, |
17 | ty::{Ty, TypeCtor}, | 16 | ty::{Ty, TypeCtor}, |
18 | AssocItem, Crate, Function, Module, Mutability, Name, Trait, | 17 | AssocItem, Crate, Function, Module, Mutability, Name, Trait, |
19 | }; | 18 | }; |
20 | 19 | ||
20 | use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; | ||
21 | |||
21 | /// This is used as a key for indexing impls. | 22 | /// This is used as a key for indexing impls. |
22 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | 23 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
23 | pub enum TyFingerprint { | 24 | pub enum TyFingerprint { |
@@ -140,14 +141,12 @@ fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayV | |||
140 | TypeCtor::Adt(def_id) => Some(std::iter::once(def_id.krate(db)?).collect()), | 141 | TypeCtor::Adt(def_id) => Some(std::iter::once(def_id.krate(db)?).collect()), |
141 | TypeCtor::Bool => lang_item_crate!(db, cur_crate, "bool"), | 142 | TypeCtor::Bool => lang_item_crate!(db, cur_crate, "bool"), |
142 | TypeCtor::Char => lang_item_crate!(db, cur_crate, "char"), | 143 | TypeCtor::Char => lang_item_crate!(db, cur_crate, "char"), |
143 | TypeCtor::Float(UncertainFloatTy::Known(f)) => match f.bitness { | 144 | TypeCtor::Float(Uncertain::Known(f)) => match f.bitness { |
144 | // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) | 145 | // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) |
145 | FloatBitness::X32 => lang_item_crate!(db, cur_crate, "f32", "f32_runtime"), | 146 | FloatBitness::X32 => lang_item_crate!(db, cur_crate, "f32", "f32_runtime"), |
146 | FloatBitness::X64 => lang_item_crate!(db, cur_crate, "f64", "f64_runtime"), | 147 | FloatBitness::X64 => lang_item_crate!(db, cur_crate, "f64", "f64_runtime"), |
147 | }, | 148 | }, |
148 | TypeCtor::Int(UncertainIntTy::Known(i)) => { | 149 | TypeCtor::Int(Uncertain::Known(i)) => lang_item_crate!(db, cur_crate, i.ty_to_string()), |
149 | lang_item_crate!(db, cur_crate, i.ty_to_string()) | ||
150 | } | ||
151 | TypeCtor::Str => lang_item_crate!(db, cur_crate, "str_alloc", "str"), | 150 | TypeCtor::Str => lang_item_crate!(db, cur_crate, "str_alloc", "str"), |
152 | TypeCtor::Slice => lang_item_crate!(db, cur_crate, "slice_alloc", "slice"), | 151 | TypeCtor::Slice => lang_item_crate!(db, cur_crate, "slice_alloc", "slice"), |
153 | TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!(db, cur_crate, "const_ptr"), | 152 | TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!(db, cur_crate, "const_ptr"), |
diff --git a/crates/ra_hir/src/ty/primitive.rs b/crates/ra_hir/src/ty/primitive.rs index 7362de4c3..47789db87 100644 --- a/crates/ra_hir/src/ty/primitive.rs +++ b/crates/ra_hir/src/ty/primitive.rs | |||
@@ -4,44 +4,38 @@ use std::fmt; | |||
4 | 4 | ||
5 | pub use hir_def::builtin_type::{FloatBitness, IntBitness, Signedness}; | 5 | pub use hir_def::builtin_type::{FloatBitness, IntBitness, Signedness}; |
6 | 6 | ||
7 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | 7 | #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] |
8 | pub enum UncertainIntTy { | 8 | pub enum Uncertain<T> { |
9 | Unknown, | 9 | Unknown, |
10 | Known(IntTy), | 10 | Known(T), |
11 | } | 11 | } |
12 | 12 | ||
13 | impl From<IntTy> for UncertainIntTy { | 13 | impl From<IntTy> for Uncertain<IntTy> { |
14 | fn from(ty: IntTy) -> Self { | 14 | fn from(ty: IntTy) -> Self { |
15 | UncertainIntTy::Known(ty) | 15 | Uncertain::Known(ty) |
16 | } | 16 | } |
17 | } | 17 | } |
18 | 18 | ||
19 | impl fmt::Display for UncertainIntTy { | 19 | impl fmt::Display for Uncertain<IntTy> { |
20 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 20 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
21 | match *self { | 21 | match *self { |
22 | UncertainIntTy::Unknown => write!(f, "{{integer}}"), | 22 | Uncertain::Unknown => write!(f, "{{integer}}"), |
23 | UncertainIntTy::Known(ty) => write!(f, "{}", ty), | 23 | Uncertain::Known(ty) => write!(f, "{}", ty), |
24 | } | 24 | } |
25 | } | 25 | } |
26 | } | 26 | } |
27 | 27 | ||
28 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | 28 | impl From<FloatTy> for Uncertain<FloatTy> { |
29 | pub enum UncertainFloatTy { | ||
30 | Unknown, | ||
31 | Known(FloatTy), | ||
32 | } | ||
33 | |||
34 | impl From<FloatTy> for UncertainFloatTy { | ||
35 | fn from(ty: FloatTy) -> Self { | 29 | fn from(ty: FloatTy) -> Self { |
36 | UncertainFloatTy::Known(ty) | 30 | Uncertain::Known(ty) |
37 | } | 31 | } |
38 | } | 32 | } |
39 | 33 | ||
40 | impl fmt::Display for UncertainFloatTy { | 34 | impl fmt::Display for Uncertain<FloatTy> { |
41 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 35 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
42 | match *self { | 36 | match *self { |
43 | UncertainFloatTy::Unknown => write!(f, "{{float}}"), | 37 | Uncertain::Unknown => write!(f, "{{float}}"), |
44 | UncertainFloatTy::Known(ty) => write!(f, "{}", ty), | 38 | Uncertain::Known(ty) => write!(f, "{}", ty), |
45 | } | 39 | } |
46 | } | 40 | } |
47 | } | 41 | } |