Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / libgo / go / go / types / conversions.go
1 // Copyright 2012 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // This file implements typechecking of conversions.
6
7 package types
8
9 import (
10         "go/ast"
11 )
12
13 // conversion typechecks the type conversion conv to type typ. iota is the current
14 // value of iota or -1 if iota doesn't have a value in the current context. The result
15 // of the conversion is returned via x. If the conversion has type errors, the returned
16 // x is marked as invalid (x.mode == invalid).
17 //
18 func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type, iota int) {
19         // all conversions have one argument
20         if len(conv.Args) != 1 {
21                 check.invalidOp(conv.Pos(), "%s conversion requires exactly one argument", conv)
22                 goto Error
23         }
24
25         // evaluate argument
26         check.expr(x, conv.Args[0], nil, iota)
27         if x.mode == invalid {
28                 goto Error
29         }
30
31         if x.mode == constant && isConstType(typ) {
32                 // constant conversion
33                 // TODO(gri) implement this
34         } else {
35                 // non-constant conversion
36                 if !x.isConvertible(typ) {
37                         check.invalidOp(conv.Pos(), "cannot convert %s to %s", x, typ)
38                         goto Error
39                 }
40                 x.mode = value
41         }
42
43         x.expr = conv
44         x.typ = typ
45         return
46
47 Error:
48         x.mode = invalid
49 }
50
51 func (x *operand) isConvertible(T Type) bool {
52         // "x is assignable to T"
53         if x.isAssignable(T) {
54                 return true
55         }
56
57         // "x's type and T have identical underlying types"
58         V := x.typ
59         Vu := underlying(V)
60         Tu := underlying(T)
61         if IsIdentical(Vu, Tu) {
62                 return true
63         }
64
65         // "x's type and T are unnamed pointer types and their pointer base types have identical underlying types"
66         if V, ok := V.(*Pointer); ok {
67                 if T, ok := T.(*Pointer); ok {
68                         if IsIdentical(underlying(V.Base), underlying(T.Base)) {
69                                 return true
70                         }
71                 }
72         }
73
74         // "x's type and T are both integer or floating point types"
75         if (isInteger(V) || isFloat(V)) && (isInteger(T) || isFloat(T)) {
76                 return true
77         }
78
79         // "x's type and T are both complex types"
80         if isComplex(V) && isComplex(T) {
81                 return true
82         }
83
84         // "x is an integer or a slice of bytes or runes and T is a string type"
85         if (isInteger(V) || isBytesOrRunes(Vu)) && isString(T) {
86                 return true
87         }
88
89         // "x is a string and T is a slice of bytes or runes"
90         if isString(V) && isBytesOrRunes(Tu) {
91                 return true
92         }
93
94         // package unsafe:
95         // "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer"
96         if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(T) {
97                 return true
98         }
99         // "and vice versa"
100         if isUnsafePointer(V) && (isPointer(Tu) || isUintptr(Tu)) {
101                 return true
102         }
103
104         return false
105 }
106
107 func isUintptr(typ Type) bool {
108         t, ok := typ.(*Basic)
109         return ok && t.Kind == Uintptr
110 }
111
112 func isUnsafePointer(typ Type) bool {
113         t, ok := typ.(*Basic)
114         return ok && t.Kind == UnsafePointer
115 }
116
117 func isPointer(typ Type) bool {
118         _, ok := typ.(*Pointer)
119         return ok
120 }
121
122 func isBytesOrRunes(typ Type) bool {
123         if s, ok := typ.(*Slice); ok {
124                 t, ok := underlying(s.Elt).(*Basic)
125                 return ok && (t.Kind == Byte || t.Kind == Rune)
126         }
127         return false
128 }